提交 fc7f75ae 编写于 作者: W wuzewu

Merge branch 'develop' of https://github.com/PaddlePaddle/PaddleHub into develop

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import argparse
import io, re
import sys, os
import subprocess
import platform
COPYRIGHT = '''
Copyright (c) 2019 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.
'''
LANG_COMMENT_MARK = None
NEW_LINE_MARK = None
COPYRIGHT_HEADER = None
if platform.system() == "Windows":
NEW_LINE_MARK = "\r\n"
else:
NEW_LINE_MARK = '\n'
COPYRIGHT_HEADER = COPYRIGHT.split(NEW_LINE_MARK)[1]
p = re.search('(\d{4})', COPYRIGHT_HEADER).group(0)
process = subprocess.Popen(["date", "+%Y"], stdout=subprocess.PIPE)
date, err = process.communicate()
date = date.decode("utf-8").rstrip("\n")
COPYRIGHT_HEADER = COPYRIGHT_HEADER.replace(p, date)
def generate_copyright(template, lang='C'):
if lang == 'Python':
LANG_COMMENT_MARK = '#'
else:
LANG_COMMENT_MARK = "//"
lines = template.split(NEW_LINE_MARK)
BLANK = " "
ans = LANG_COMMENT_MARK + BLANK + COPYRIGHT_HEADER + NEW_LINE_MARK
for lino, line in enumerate(lines):
if lino == 0 or lino == 1 or lino == len(lines) - 1: continue
if len(line) == 0:
BLANK = ""
else:
BLANK = " "
ans += LANG_COMMENT_MARK + BLANK + line + NEW_LINE_MARK
return ans + "\n"
def lang_type(filename):
if filename.endswith(".py"):
return "Python"
elif filename.endswith(".h"):
return "C"
elif filename.endswith(".c"):
return "C"
elif filename.endswith(".hpp"):
return "C"
elif filename.endswith(".cc"):
return "C"
elif filename.endswith(".cpp"):
return "C"
elif filename.endswith(".cu"):
return "C"
elif filename.endswith(".cuh"):
return "C"
elif filename.endswith(".go"):
return "C"
elif filename.endswith(".proto"):
return "C"
else:
print("Unsupported filetype %s", filename)
exit(0)
PYTHON_ENCODE = re.compile("^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)")
def main(argv=None):
parser = argparse.ArgumentParser(
description='Checker for copyright declaration.')
parser.add_argument('filenames', nargs='*', help='Filenames to check')
args = parser.parse_args(argv)
retv = 0
for filename in args.filenames:
fd = io.open(filename, encoding="utf-8")
first_line = fd.readline()
second_line = fd.readline()
if "COPYRIGHT (C)" in first_line.upper(): continue
if first_line.startswith("#!") or PYTHON_ENCODE.match(
second_line) != None or PYTHON_ENCODE.match(first_line) != None:
continue
original_contents = io.open(filename, encoding="utf-8").read()
new_contents = generate_copyright(
COPYRIGHT, lang_type(filename)) + original_contents
print('Auto Insert Copyright Header {}'.format(filename))
retv = 1
with io.open(filename, 'w') as output_file:
output_file.write(new_contents)
return retv
if __name__ == '__main__':
exit(main())
---
name: 需求反馈
about: 需求建议
title: ''
labels: ''
assignees: ''
---
欢迎您对PaddleHub提出建议,非常感谢您对PaddleHub的贡献!
在留下您的建议时,辛苦您同步提供如下信息:
- 您想要增加什么新特性?
- 什么样的场景下需要该特性?
- 没有该特性的条件下,PaddleHub目前是否能间接满足该需求?
- 增加该特性,PaddleHub可能需要变化的部分。
- 如果可以的话,简要描述下您的解决方案
---
name: BUG反馈
about: PaddleHub Bug反馈
title: ''
labels: ''
assignees: ''
---
欢迎您反馈PaddleHub使用问题,非常感谢您对PaddleHub的贡献!
在留下您的问题时,辛苦您同步提供如下信息:
- 版本、环境信息
1)PaddleHub和PaddlePaddle版本:请提供您的PaddleHub和PaddlePaddle版本号,例如PaddleHub1.4.1,PaddlePaddle1.6.2
2)系统环境:请您描述系统类型,例如Linux/Windows/MacOS/,python版本
- 复现信息:如为报错,请给出复现环境、复现步骤
...@@ -30,12 +30,3 @@ ...@@ -30,12 +30,3 @@
- --show-source - --show-source
- --statistics - --statistics
files: \.py$ files: \.py$
- repo: local
hooks:
- id: copyright_checker
name: copyright_checker
entry: python ./.copyright.hook
language: system
files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|proto|py)$
exclude: (?!.*third_party)^.*$
...@@ -16,19 +16,18 @@ jobs: ...@@ -16,19 +16,18 @@ jobs:
os: linux os: linux
python: 3.6 python: 3.6
script: /bin/bash ./scripts/check_code_style.sh script: /bin/bash ./scripts/check_code_style.sh
- name: "CI on Linux/Python3.5"
os: linux
python: 3.5
- name: "CI on Linux/Python2.7"
os: linux
python: 2.7
env: env:
- PYTHONPATH=${PWD} - PYTHONPATH=${PWD}
install: install:
- pip install --upgrade paddlepaddle - if [[ $TRAVIS_OS_NAME == osx ]]; then
- pip install -r requirements.txt pip3 install --upgrade paddlepaddle;
pip3 install -r requirements.txt;
else
pip install --upgrade paddlepaddle;
pip install -r requirements.txt;
fi
notifications: notifications:
email: email:
......
...@@ -5,3 +5,4 @@ ...@@ -5,3 +5,4 @@
| sjtubinlong | Bin Long | | sjtubinlong | Bin Long |
| Steffy-zxf | Xuefei Zhang | | Steffy-zxf | Xuefei Zhang |
| kinghuin | Jinxuan Qiu | | kinghuin | Jinxuan Qiu |
| ShenYuhan | Yuhan Shen |
# PaddleHub <p align="center">
<img src="./docs/imgs/paddlehub_logo.jpg" align="middle"
</p>
[![Build Status](https://travis-ci.org/PaddlePaddle/PaddleHub.svg?branch=release/v1.3)](https://travis-ci.org/PaddlePaddle/PaddleHub) [![Build Status](https://travis-ci.org/PaddlePaddle/PaddleHub.svg?branch=release/v1.6)](https://travis-ci.org/PaddlePaddle/PaddleHub)
[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE) [![License](https://img.shields.io/badge/license-Apache%202-red.svg)](LICENSE)
[![Version](https://img.shields.io/github/release/PaddlePaddle/PaddleHub.svg)](https://github.com/PaddlePaddle/PaddleHub/releases) [![Version](https://img.shields.io/github/release/PaddlePaddle/PaddleHub.svg)](https://github.com/PaddlePaddle/PaddleHub/releases)
![python version](https://img.shields.io/badge/python-3.6+-orange.svg)
![support os](https://img.shields.io/badge/os-linux%2C%20win%2C%20mac-yellow.svg)
PaddleHub是飞桨生态的预训练模型应用工具,开发者可以便捷地使用高质量的预训练模型结合Fine-tune API快速完成模型迁移到部署的全流程工作。PaddleHub提供的预训练模型涵盖了图像分类、目标检测、词法分析、语义模型、情感分析、视频分类、图像生成、图像分割、文本审核、关键点检测等主流模型。更多详情可查看官网:https://www.paddlepaddle.org.cn/hub
PaddleHub以预训练模型应用为核心具备以下特点:
* **[模型即软件](#模型即软件)**,通过Python API或命令行实现模型调用,可快速体验或集成飞桨特色预训练模型。
* **[易用的迁移学习](#易用的迁移学习)**,通过Fine-tune API,内置多种优化策略,只需少量代码即可完成预训练模型的Fine-tuning。
* **[一键模型转服务](#一键模型转服务)**,简单一行命令即可搭建属于自己的深度学习模型API服务完成部署。
* **[自动超参优化](#自动超参优化)**,内置AutoDL Finetuner能力,一键启动自动化超参搜索。
<p align="center">
<img src="./docs/imgs/paddlehub_finetune.gif" align="middle"
</p>
<p align='center'>
十行代码完成ERNIE工业级文本分类
</p>
PaddleHub是基于PaddlePaddle生态下的预训练模型管理和迁移学习工具,可以结合预训练模型更便捷地开展迁移学习工作。PaddleHub特性:
* 便捷地获取PaddlePaddle生态下的所有预训练模型,涵盖了图像分类、目标检测、词法分析、语义模型、情感分析、语言模型、视频分类、图像生成、图像分割等主流模型。
* 更多详情可查看官网:https://www.paddlepaddle.org.cn/hub
* 通过PaddleHub Fine-tune API,结合少量代码即可完成**大规模预训练模型**的迁移学习,具体Demo可参考以下链接:
* [文本分类](./demo/text-classification)
* [序列标注](./demo/sequence-labeling)
* [多标签分类](./demo/multi-label-classification)
* [图像分类](./demo/image-classification)
* [检索式问答任务](./demo/qa_classification)
* [回归任务](./demo/sentence_similarity)
* [句子语义相似度计算](./demo/sentence_similarity)
* [阅读理解任务](./demo/reading-comprehension)
* 支持超参优化(AutoDL Finetuner),自动调整超参数,给出效果较佳的超参数组合。
* [PaddleHub超参优化功能AutoDL Finetuner使用示例](./demo/autofinetune)
* 引入『**模型即软件**』的设计理念,通过Python API或者命令行实现一键预测,更方便地应用PaddlePaddle模型库。
* [PaddleHub命令行工具介绍](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B7%A5%E5%85%B7)
* 一键Module服务化部署 - HubServing
* [PaddleHub-Serving一键服务部署](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub-Serving%E4%B8%80%E9%94%AE%E6%9C%8D%E5%8A%A1%E9%83%A8%E7%BD%B2)
* [使用示例](./demo/serving)
## 目录 ## 目录
* [安装](#%E5%AE%89%E8%A3%85) * [安装](#%E5%AE%89%E8%A3%85)
* [快速体验](#%E5%BF%AB%E9%80%9F%E4%BD%93%E9%AA%8C) * [特性](#特性)
* [教程](#%E6%95%99%E7%A8%8B)
* [FAQ](#faq) * [FAQ](#faq)
* [用户交流群](#%E7%94%A8%E6%88%B7%E4%BA%A4%E6%B5%81%E7%BE%A4) * [用户交流群](#%E7%94%A8%E6%88%B7%E4%BA%A4%E6%B5%81%E7%BE%A4)
* [更新历史](#%E6%9B%B4%E6%96%B0%E5%8E%86%E5%8F%B2) * [更新历史](#%E6%9B%B4%E6%96%B0%E5%8E%86%E5%8F%B2)
...@@ -38,131 +43,166 @@ PaddleHub是基于PaddlePaddle生态下的预训练模型管理和迁移学习 ...@@ -38,131 +43,166 @@ PaddleHub是基于PaddlePaddle生态下的预训练模型管理和迁移学习
## 安装 ## 安装
### 环境依赖 ### 环境依赖
* Python==2.7 or Python>=3.5 for Linux or Mac
**Python>=3.6 for Windows**
* PaddlePaddle>=1.5 * Python >= 3.6
* PaddlePaddle >= 1.7.0
* 操作系统: Windows/Mac/Linux
除上述依赖外,PaddleHub的预训练模型和预置数据集需要连接服务端进行下载,请确保机器可以正常访问网络。若本地已存在相关的数据集和预训练模型,则可以离线运行PaddleHub。 ### 安装命令
**NOTE:** 在安装PaddleHub之前,请先安装PaddlePaddle深度学习框架,更多安装说明请查阅[飞桨快速安装](https://www.paddlepaddle.org.cn/install/quick)
1. 若是出现离线运行PaddleHub错误,请更新PaddleHub 1.1.1版本之上。
pip安装方式如下:
```shell ```shell
$ pip install paddlehub pip install paddlehub
``` ```
2. 下载数据集、module等,PaddleHub要求机器可以访问外网。可以使用server_check()可以检查本地与远端PaddleHub-Server的连接状态,使用方法如下:
```python 除上述依赖外,预训练模型和数据集的下载需要网络连接,请确保机器可以**正常访问网络**。若本地已存在相关预训练模型目录,则可以离线使用PaddleHub。
import paddlehub
paddlehub.server_check() ## 特性
# 如果可以连接远端PaddleHub-Server,则显示Request Hub-Server successfully.
# 如果无法连接远端PaddleHub-Server,则显示Request Hub-Server unsuccessfully. ### 模型即软件
```
PaddleHub采用模型即软件的设计理念,所有的预训练模型与Python软件包类似,具备版本的概念,通过`hub install/uninstall` 可以便捷完成模型的升级和卸载。还可以通过Python的API或命令行实现快速预测的软件集成,更方便地应用和集成深度学习模型。
安装PaddleHub后,执行命令[hub run](./docs/tutorial/cmdintro.md),即可快速体验无需代码、一键预测的功能:
## 快速体验 * 使用[文字识别](https://www.paddlepaddle.org.cn/hublist?filter=en_category&value=TextRecognition)轻量级中文OCR模型chinese_ocr_db_crnn_mobile即可一键快速识别图片中的文字。
安装成功后,执行下面的命令,可以快速体验PaddleHub无需代码、一键预测的命令行功能: ```shell
$ wget https://paddlehub.bj.bcebos.com/model/image/ocr/test_ocr.jpg
$ hub run chinese_ocr_db_crnn_mobile --input_path test_ocr.jpg --visualization=True
```
预测结果图片保存在当前运行路径下ocr_result文件夹中,如下图所示。
`示例一` <p align="center">
<img src="./docs/imgs/ocr_res.jpg" width='70%' align="middle"
</p>
使用[词法分析](http://www.paddlepaddle.org.cn/hub?filter=category&value=LexicalAnalysis)模型LAC进行分词 * 使用[目标检测](https://www.paddlepaddle.org.cn/hublist?filter=en_category&value=ObjectDetection)模型pyramidbox_lite_mobile_mask对图片进行口罩检测
```shell ```shell
$ hub run lac --input_text "今天是个好日子" $ wget https://paddlehub.bj.bcebos.com/resources/test_mask_detection.jpg
[{'word': ['今天', '是', '个', '好日子'], 'tag': ['TIME', 'v', 'q', 'n']}] $ hub run pyramidbox_lite_mobile_mask --input_path test_mask_detection.jpg
``` ```
<p align="center">
<img src="./docs/imgs/test_mask_detection_result.jpg" align="middle"
</p>
`示例二` * 使用[词法分析](https://www.paddlepaddle.org.cn/hublist?filter=en_category&value=LexicalAnalysis)模型LAC进行分词
```shell
$ hub run lac --input_text "现在,慕尼黑再保险公司不仅是此类行动的倡议者,更是将其大量气候数据整合进保险产品中,并与公众共享大量天气信息,参与到新能源领域的保障中。"
[{
'word': ['现在', ',', '慕尼黑再保险公司', '不仅', '是', '此类', '行动', '的', '倡议者', ',', '更是', '将', '其', '大量', '气候', '数据', '整合', '进', '保险', '产品', '中', ',', '并', '与', '公众', '共享', '大量', '天气', '信息', ',', '参与', '到', '新能源', '领域', '的', '保障', '中', '。'],
'tag': ['TIME', 'w', 'ORG', 'c', 'v', 'r', 'n', 'u', 'n', 'w', 'd', 'p', 'r', 'a', 'n', 'n', 'v', 'v', 'n', 'n', 'f', 'w', 'c', 'p', 'n', 'v', 'a', 'n', 'n', 'w', 'v', 'v', 'n', 'n', 'u', 'vn', 'f', 'w']
}]
```
使用[情感分析](http://www.paddlepaddle.org.cn/hub?filter=category&value=SentimentAnalysis)模型Senta对句子进行情感预测 * 使用[情感分析](https://www.paddlepaddle.org.cn/hublist?filter=en_category&value=SentimentAnalysis)模型Senta对句子进行情感预测
```shell ```shell
$ hub run senta_bilstm --input_text "今天天气真好" $ hub run senta_bilstm --input_text "今天天气真好"
{'text': '今天天气真好', 'sentiment_label': 1, 'sentiment_key': 'positive', 'positive_probs': 0.9798, 'negative_probs': 0.0202}] {'text': '今天天气真好', 'sentiment_label': 1, 'sentiment_key': 'positive', 'positive_probs': 0.9798, 'negative_probs': 0.0202}]
``` ```
`示例三` * 使用[目标检测](https://www.paddlepaddle.org.cn/hublist?filter=en_category&value=ObjectDetection)模型Ultra-Light-Fast-Generic-Face-Detector-1MB对图片进行人脸识别
```shell
$ wget https://paddlehub.bj.bcebos.com/resources/test_image.jpg
$ hub run ultra_light_fast_generic_face_detector_1mb_640 --input_path test_image.jpg
```
<p align="center">
<img src="./docs/imgs/face_detection_result.jpeg" align="middle"
</p>
* 使用[图像分割](https://www.paddlepaddle.org.cn/hublist?filter=en_category&value=ImageSegmentation)模型进行人像扣图和人体部件识别
使用[目标检测](http://www.paddlepaddle.org.cn/hub?filter=category&value=ObjectDetection)模型 SSD/YOLO v3/Faster RCNN 对图片进行目标检测
```shell ```shell
$ wget --no-check-certificate https://paddlehub.bj.bcebos.com/resources/test_object_detection.jpg $ wget https://paddlehub.bj.bcebos.com/resources/test_image.jpg
$ hub run ssd_mobilenet_v1_pascal --input_path test_object_detection.jpg $ hub run ace2p --input_path test_image.jpg
$ hub run yolov3_coco2017 --input_path test_object_detection.jpg $ hub run deeplabv3p_xception65_humanseg --input_path test_image.jpg
$ hub run faster_rcnn_coco2017 --input_path test_object_detection.jpg
``` ```
![SSD检测结果](https://raw.githubusercontent.com/PaddlePaddle/PaddleHub/release/v1.3/docs/imgs/object_detection_result.png)
除了上述三类模型外,PaddleHub还发布了语言模型、语义模型、图像分类、生成模型、视频分类等业界主流模型,更多PaddleHub已经发布的模型,请前往 https://www.paddlepaddle.org.cn/hub 查看 <p align="center">
<img src="./docs/imgs/img_seg_result.jpeg" width="35%" />
<img src="./docs/imgs/humanseg_test_res.png" width="35%" />
</p>
同时,我们在AI Studio上提供了IPython NoteBook形式的demo,您可以直接在平台上在线体验,链接如下: <p align='center'>
&#8194;&#8194;&#8194&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;ACE2P人体部件分割&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;&#8194;
HumanSeg人像分割&#8194;&#8194;&#8194;
</p>
|类别|AIStudio链接| PaddleHub还提供图像分类、语义模型、视频分类、图像生成、图像分割、文本审核、关键点检测等主流模型,更多模型介绍,请前往[预训练模型介绍](./docs/pretrained_models.md)或者PaddleHub官网[https://www.paddlepaddle.org.cn/hub](https://www.paddlepaddle.org.cn/hub) 查看
|-|-|
|ERNIE Tiny 文本分类|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/186443)
|ERNIE文本分类|[点击体验](https://aistudio.baidu.com/aistudio/projectDetail/79380)|
|ERNIE序列标注|[点击体验](https://aistudio.baidu.com/aistudio/projectDetail/79377)|
|ELMo文本分类|[点击体验](https://aistudio.baidu.com/aistudio/projectDetail/79400)|
|senta情感分类|[点击体验](https://aistudio.baidu.com/aistudio/projectDetail/79398)|
|图像分类| [点击体验](https://aistudio.baidu.com/aistudio/projectDetail/79378)|
|自定义数据FineTune(序列标注任务)|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/184200)|
|自定义数据FineTune(文本分类任务)|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/185121) |
### 易用的迁移学习
## 教程 通过Fine-tune API,只需要少量代码即可完成深度学习模型在自然语言处理和计算机视觉场景下的迁移学习。
PaddleHub Fine-tune API 详情参考[wiki教程](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub-Finetune-API) * [Demo示例](./demo)提供丰富的Fine-tune API的使用代码,包括[文本分类](./demo/text_classification)[序列标注](./demo/sequence_labeling)[多标签分类](./demo/multi_label_classification)[图像分类](./demo/image_classification)[检索式问答任务](./demo/qa_classification)[回归任务](./demo/regression)[句子语义相似度计算](./demo/sentence_similarity)[阅读理解任务](./demo/reading_comprehension)等场景的模型迁移示例。
PaddleHub如何完成迁移学习,详情参考[wiki教程](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub%E4%B8%8E%E8%BF%81%E7%A7%BB%E5%AD%A6%E4%B9%A0) * 如需在线快速体验,请点击[PaddleHub教程合集](https://aistudio.baidu.com/aistudio/projectdetail/231146),可使用AI Studio平台提供的GPU算力进行快速尝试。
PaddleHub如何自定义迁移任务,详情参考[wiki教程](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub:-%E8%87%AA%E5%AE%9A%E4%B9%89Task) 更多Fine-tune API的使用教程可参考:
PaddleHub如何自动优化超参数,详情参考[AutoDL Finetuner使用教程](https://github.com/PaddlePaddle/PaddleHub/blob/release/v1.3/tutorial/autofinetune.md) * [Fine-tune API](./docs/reference)
PaddleHub如何使用ULMFiT策略微调预训练模型,详情参考[PaddleHub 迁移学习与ULMFiT微调策略](https://github.com/PaddlePaddle/PaddleHub/blob/release/v1.3/tutorial/strategy_exp.md) * [如何对自定义数据集进行Fine-tuning](./docs/tutorial/how_to_load_data.md)
## FAQ * [如何自定义迁移任务](./docs/tutorial/how_to_define_task.md)
**Q:** 利用PaddleHub ernie/bert进行Finetune时,运行出错并提示`paddle.fluid.core_avx.EnforceNotMet: Input ShapeTensor cannot be found in Op reshape2`等信息 * [ULMFiT优化策略](./docs/tutorial/strategy_exp.md)
### 一键模型转服务
PaddleHub提供便捷的模型转服务的能力,只需简单一行命令即可完成模型的HTTP服务部署。通过以下命令即可快速启动LAC词法分析服务:
**A:** 因为ernie/bert module的创建时和此时运行环境中PaddlePaddle版本不对应。可以将PaddlePaddle和PaddleHub升级至最新版本,同时将ernie卸载。
```shell ```shell
$ pip install --upgrade paddlehub $ hub serving start --modules lac
$ hub uninstall ernie
``` ```
**Q:** 使用PaddleHub时,无法下载预置数据集、Module的等现象 更多关于模型服务化使用说明参见[PaddleHub模型一键能服务化部署](./docs/tutorial/serving.md)
**A:** PaddleHub中的预训练模型和预置数据集都需要通过服务端进行下载,因此PaddleHub默认用户访问外网权限。 **PaddleHub 1.5.0版本增加文本Embedding服务[Bert Service](./docs/tutorial/bert_service.md), 高性能地获取文本Embedding**
可以通过以下命令确认是否可以访问外网。
```python ### 自动超参优化
import requests
res = requests.get('http://paddlepaddle.org.cn/paddlehub/search', {'word': 'ernie', 'type': 'Module'}) PaddleHub内置AutoDL Finetuner能力,提供多种优化策略策略实现自动化超参搜索,使得模型在验证集上得到更好的结果,用户只需要一行命令`hub autofinetune`即可启动。更多详细使用说明请参见[PaddleHub超参优化](./docs/tutorial/autofinetune.md)
print(res)
# the common result is like this: ## FAQ
# <Response [200]>
``` **Q:** 利用PaddleHub Fine-tune如何适配自定义数据集?
**Note:** PaddleHub 1.1.1版本已支持离线运行Module
**A:** 参考[PaddleHub适配自定义数据集完成Fine-tune](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)
**Q:** 利用PaddleHub Finetune如何适配自定义数据集
**A:** 参考[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) **Q:** 使用PaddleHub时,无法下载预置数据集、Module的等现象。
**A:** 下载数据集、module等,PaddleHub要求机器可以访问外网。可以使用server_check()可以检查本地与远端PaddleHub-Server的连接状态,使用方法如下:
```python
import paddlehub
paddlehub.server_check()
# 如果可以连接远端PaddleHub-Server,则显示Request Hub-Server successfully。
# 如果无法连接远端PaddleHub-Server,则显示Request Hub-Server unsuccessfully。
```
**Q:** 利用PaddleHub ERNIE/BERT进行Fine-tune时,运行出错并提示`paddle.fluid.core_avx.EnforceNotMet: Input ShapeTensor cannot be found in Op reshape2`等信息。
**A:** 预训练模型版本与PaddlePaddle版本不匹配。可尝试将PaddlePaddle和PaddleHub升级至最新版本,并将原ERNIE模型卸载。
```shell
$ pip install --upgrade paddlehub
$ hub uninstall ernie
```
**更多问题** **FAQ**
当安装或者使用遇到问题时,可以通过[FAQ](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub-FAQ)查找解决方案。 当安装或者使用遇到问题时,可以通过[FAQ](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub-FAQ)查找解决方案。
如果在FAQ中没有找到解决方案,欢迎您将问题和bug报告以[Github Issues](https://github.com/PaddlePaddle/PaddleHub/issues)的形式提交给我们,我们会第一时间进行跟进 如果在FAQ中没有找到解决方案,欢迎您将问题[Github Issues](https://github.com/PaddlePaddle/PaddleHub/issues)的形式提交给我们,我们会第一时间进行跟进。
## 用户交流群 ## 用户交流群
* 飞桨PaddlePaddle 交流群:796771754(QQ群) * 飞桨PaddlePaddle 交流群:796771754(QQ群)
* 飞桨 ERNIE交流群:760439550(QQ群) * 飞桨ERNIE交流群:760439550(QQ群)
## 更新历史 ## 更新历史
详情参考[更新历史](./RELEASE.md) PaddleHub v1.7 已发布!
更多升级详情参考[更新历史](./RELEASE.md)
## `v1.7.0`
* 丰富预训练模型,提升应用性
* 新增VENUS系列视觉预训练模型[yolov3_darknet53_venus](https://www.paddlepaddle.org.cn/hubdetail?name=yolov3_darknet53_venus&en_category=ObjectDetection)[faster_rcnn_resnet50_fpn_venus](https://www.paddlepaddle.org.cn/hubdetail?name=faster_rcnn_resnet50_fpn_venus&en_category=ObjectDetection),可大幅度提升图像分类和目标检测任务的Fine-tune效果
* 新增工业级短视频分类模型[videotag_tsn_lstm](https://paddlepaddle.org.cn/hubdetail?name=videotag_tsn_lstm&en_category=VideoClassification),支持3000类中文标签识别
* 新增轻量级中文OCR模型[chinese_ocr_db_rcnn](https://www.paddlepaddle.org.cn/hubdetail?name=chinese_ocr_db_rcnn&en_category=TextRecognition)[chinese_text_detection_db](https://www.paddlepaddle.org.cn/hubdetail?name=chinese_text_detection_db&en_category=TextRecognition),支持一键快速OCR识别
* 新增行人检测、车辆检测、动物识别、Object等工业级模型
* Fine-tune API升级
* 文本分类任务新增6个预置网络,包括CNN, BOW, LSTM, BiLSTM, DPCNN等
* 使用VisualDL可视化训练评估性能数据
## `v1.6.2`
* 修复图像分类在windows下运行错误
## `v1.6.1`
* 修复windows下安装PaddleHub缺失config.json文件
# `v1.6.0`
* NLP Module全面升级,提升应用性和灵活性
* lac、senta系列(bow、cnn、bilstm、gru、lstm)、simnet_bow、porn_detection系列(cnn、gru、lstm)升级高性能预测,性能提升高达50%
* ERNIE、BERT、RoBERTa等Transformer类语义模型新增获取预训练embedding接口get_embedding,方便接入下游任务,提升应用性
* 新增RoBERTa通过模型结构压缩得到的3层Transformer模型[rbt3](https://www.paddlepaddle.org.cn/hubdetail?name=rbt3&en_category=SemanticModel)[rbtl3](https://www.paddlepaddle.org.cn/hubdetail?name=rbtl3&en_category=SemanticModel)
* Task predict接口增加高性能预测模式accelerate_mode,性能提升高达90%
* PaddleHub Module创建流程开放,支持Fine-tune模型转化,全面提升应用性和灵活性
* [预训练模型转化为PaddleHub Module教程](./docs/contribution/contri_pretrained_model.md)
* [Fine-tune模型转化为PaddleHub Module教程](./docs/tutorial/finetuned_model_to_module.md)
* [PaddleHub Serving](/docs/tutorial/serving.md)优化启动方式,支持更加灵活的参数配置
# `v1.5.4`
* 修复Fine-tune中断,checkpoint文件恢复训练失败的问题
# `v1.5.3`
* 优化口罩模型输出结果,提供更加灵活的部署及调用方式
# `v1.5.2`
* 优化pyramidbox_lite_server_mask、pyramidbox_lite_mobile_mask模型的服务化部署性能
# `v1.5.1`
* 修复加载module缺少cache目录的问题
# `v1.5.0`
* 升级PaddleHub Serving,提升性能和易用性
* 新增文本Embedding服务[Bert Service](./tutorial/bert_service.md), 轻松获取文本embedding;
* 代码精短,易于使用。服务端/客户端一行命令即可获取文本embedding;
* 更高性能,更高效率。通过Paddle AnalysisPredictor API优化计算图,提升速度减小显存占用
* 随"机"应变,灵活扩展。根据机器资源和实际需求可灵活增加服务端数量,支持多显卡多模型计算任务
* 优化并发方式,多核环境中使用多线程并发提高整体QPS
* 优化PaddleHub迁移学习组网Task功能,提升易用性
* 增加Hook机制,支持[修改Task内置方法](https://github.com/PaddlePaddle/PaddleHub/wiki/%E5%A6%82%E4%BD%95%E4%BF%AE%E6%94%B9Task%E5%86%85%E7%BD%AE%E6%96%B9%E6%B3%95%EF%BC%9F)
* 增加colorlog,支持日志彩色显示
* 改用save_inference_model接口保存模型,方便模型部署
* 优化predict接口,增加return_result参数,方便用户直接获取预测结果
* 优化PaddleHub Dataset基类,加载[自定义数据](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)代码更少、更简单
# `v1.4.1` # `v1.4.1`
* 修复利用Transformer类模型完成序列标注任务适配paddle1.6版本的问题 * 修复利用Transformer类模型完成序列标注任务适配paddle1.6版本的问题
...@@ -69,7 +138,7 @@ ...@@ -69,7 +138,7 @@
# `v1.0.0` # `v1.0.0`
* 全新发布PaddleHub官网,易用性全面提升 * 全新发布PaddleHub官网,易用性全面提升
* 新增网站 http://hub.paddlepaddle.org.cn 包含PaddlePaddle生态的预训练模型使用介绍 * 新增网站 https://www.paddlepaddle.org.cn/hub 包含PaddlePaddle生态的预训练模型使用介绍
* 迁移学习Demo接入AI Studio与AI Book,无需安装即可快速体验 * 迁移学习Demo接入AI Studio与AI Book,无需安装即可快速体验
* 新增29个预训练模型,覆盖文本、图像、视频三大领域;目前官方提供40个预训练模型 * 新增29个预训练模型,覆盖文本、图像、视频三大领域;目前官方提供40个预训练模型
...@@ -99,4 +168,4 @@ ...@@ -99,4 +168,4 @@
**命令行一键使用**: 无需代码,通过命令行即可直接使用预训练模型进行预测,快速调研训练模型效果。目前版本支持以下模型:词法分析LAC;情感分析Senta;目标检测SSD;图像分类ResNet, MobileNet, NASNet等。 **命令行一键使用**: 无需代码,通过命令行即可直接使用预训练模型进行预测,快速调研训练模型效果。目前版本支持以下模型:词法分析LAC;情感分析Senta;目标检测SSD;图像分类ResNet, MobileNet, NASNet等。
**迁移学习**: 提供了基于预训练模型的Finetune API,用户通过少量代码即可完成迁移学习,包括BERT/ERNIE文本分类、序列标注、图像分类迁移等。 **迁移学习**: 提供了基于预训练模型的Fine-tune API,用户通过少量代码即可完成迁移学习,包括BERT/ERNIE文本分类、序列标注、图像分类迁移等。
# DELTA: DEep Learning Transfer using Feature Map with Attention for Convolutional Networks
## Introduction
This page implements the [DELTA](https://arxiv.org/abs/1901.09229) algorithm in [PaddlePaddle](https://www.paddlepaddle.org.cn).
> Li, Xingjian, et al. "DELTA: Deep learning transfer using feature map with attention for convolutional networks." ICLR 2019.
## Preparation of Data and Pre-trained Model
- Download transfer learning target datasets, like [Caltech-256](http://www.vision.caltech.edu/Image_Datasets/Caltech256/), [CUB_200_2011](http://www.vision.caltech.edu/visipedia/CUB-200-2011.html) or others. Arrange the dataset in this way:
```
root/train/dog/xxy.jpg
root/train/dog/xxz.jpg
...
root/train/cat/nsdf3.jpg
root/train/cat/asd932_.jpg
...
root/test/dog/xxx.jpg
...
root/test/cat/123.jpg
...
```
- Download [the pretrained models](https://github.com/PaddlePaddle/models/tree/release/1.7/PaddleCV/image_classification#resnet-series). We give the results of ResNet-101 below.
## Running Scripts
Modify `global_data_path` in `datasets/data_path` to the path root where the dataset is.
```bash
python -u main.py --dataset Caltech30 --delta_reg 0.1 --wd_rate 1e-4 --batch_size 64 --outdir outdir --num_epoch 100 --use_cuda 0
python -u main.py --dataset CUB_200_2011 --delta_reg 0.1 --wd_rate 1e-4 --batch_size 64 --outdir outdir --num_epoch 100 --use_cuda 0
```
Those scripts give the results below:
\ | l2 | delta
---|---|---
Caltech-256|79.86|84.71
CUB_200|77.41|80.05
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
'--prefix', default=None, type=str, help='prefix for model id')
parser.add_argument('--dataset', default='PetImages', type=str, help='dataset')
parser.add_argument(
'--seed',
default=None,
type=int,
help='random seed (default: None, i.e., not fix the randomness).')
parser.add_argument('--batch_size', default=20, type=int, help='batch_size.')
parser.add_argument('--delta_reg', default=0.1, type=float, help='delta_reg.')
parser.add_argument('--wd_rate', default=1e-4, type=float, help='wd_rate.')
parser.add_argument(
'--use_cuda', default=0, type=int, help='use_cuda device. -1 cpu.')
parser.add_argument('--num_epoch', default=100, type=int, help='num_epoch.')
parser.add_argument('--outdir', default='outdir', type=str, help='outdir')
parser.add_argument(
'--pretrained_model',
default='./pretrained_models/ResNet101_pretrained',
type=str,
help='pretrained model pathname')
args = parser.parse_args()
global_data_path = '[root_path]/datasets'
import cv2
import numpy as np
import six
import os
import glob
def resize_short(img, target_size, interpolation=None):
"""resize image
Args:
img: image data
target_size: resize short target size
interpolation: interpolation mode
Returns:
resized image data
"""
percent = float(target_size) / min(img.shape[0], img.shape[1])
resized_width = int(round(img.shape[1] * percent))
resized_height = int(round(img.shape[0] * percent))
if interpolation:
resized = cv2.resize(
img, (resized_width, resized_height), interpolation=interpolation)
else:
resized = cv2.resize(img, (resized_width, resized_height))
return resized
def crop_image(img, target_size, center):
"""crop image
Args:
img: images data
target_size: crop target size
center: crop mode
Returns:
img: cropped image data
"""
height, width = img.shape[:2]
size = target_size
if center == True:
w_start = (width - size) // 2
h_start = (height - size) // 2
else:
w_start = np.random.randint(0, width - size + 1)
h_start = np.random.randint(0, height - size + 1)
w_end = w_start + size
h_end = h_start + size
img = img[h_start:h_end, w_start:w_end, :]
return img
def preprocess_image(img, random_mirror=True):
"""
centered, scaled by 1/255.
:param img: np.array: shape: [ns, h, w, 3], color order: rgb.
:return: np.array: shape: [ns, h, w, 3]
"""
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
# transpose to [ns, 3, h, w]
img = img.astype('float32').transpose((0, 3, 1, 2)) / 255
img_mean = np.array(mean).reshape((3, 1, 1))
img_std = np.array(std).reshape((3, 1, 1))
img -= img_mean
img /= img_std
if random_mirror:
mirror = int(np.random.uniform(0, 2))
if mirror == 1:
img = img[:, :, ::-1, :]
return img
def _find_classes(dir):
# Faster and available in Python 3.5 and above
classes = [d.name for d in os.scandir(dir) if d.is_dir()]
classes.sort()
class_to_idx = {classes[i]: i for i in range(len(classes))}
return classes, class_to_idx
class ReaderConfig():
"""
A generic data loader where the images are arranged in this way:
root/train/dog/xxy.jpg
root/train/dog/xxz.jpg
...
root/train/cat/nsdf3.jpg
root/train/cat/asd932_.jpg
...
root/test/dog/xxx.jpg
...
root/test/cat/123.jpg
...
"""
def __init__(self, dataset_dir, is_test):
image_paths, labels, self.num_classes = self.reader_creator(
dataset_dir, is_test)
random_per = np.random.permutation(range(len(image_paths)))
self.image_paths = image_paths[random_per]
self.labels = labels[random_per]
self.is_test = is_test
def get_reader(self):
def reader():
IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm',
'.tif', '.tiff', '.webp')
target_size = 256
crop_size = 224
for i, img_path in enumerate(self.image_paths):
if not img_path.lower().endswith(IMG_EXTENSIONS):
continue
img = cv2.imread(img_path)
if img is None:
print(img_path)
continue
img = resize_short(img, target_size, interpolation=None)
img = crop_image(img, crop_size, center=self.is_test)
img = img[:, :, ::-1]
img = np.expand_dims(img, axis=0)
img = preprocess_image(img, not self.is_test)
yield img, self.labels[i]
return reader
def reader_creator(self, dataset_dir, is_test=False):
IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm',
'.tif', '.tiff', '.webp')
# read
if is_test:
datasubset_dir = os.path.join(dataset_dir, 'test')
else:
datasubset_dir = os.path.join(dataset_dir, 'train')
class_names, class_to_idx = _find_classes(datasubset_dir)
# num_classes = len(class_names)
image_paths = []
labels = []
for class_name in class_names:
classes_dir = os.path.join(datasubset_dir, class_name)
for img_path in glob.glob(os.path.join(classes_dir, '*')):
if not img_path.lower().endswith(IMG_EXTENSIONS):
continue
image_paths.append(img_path)
labels.append(class_to_idx[class_name])
image_paths = np.array(image_paths)
labels = np.array(labels)
return image_paths, labels, len(class_names)
import os
import time
import sys
import math
import numpy as np
import functools
import re
import logging
import glob
import paddle
import paddle.fluid as fluid
from models.resnet import ResNet101
from datasets.readers import ReaderConfig
# import cv2
# import skimage
# import matplotlib.pyplot as plt
# from paddle.fluid.core import PaddleTensor
# from paddle.fluid.core import AnalysisConfig
# from paddle.fluid.core import create_paddle_predictor
from args import args
from datasets.data_path import global_data_path
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
if args.seed is not None:
np.random.seed(args.seed)
print(os.environ.get('LD_LIBRARY_PATH', None))
print(os.environ.get('PATH', None))
class AverageMeter(object):
"""Computes and stores the average and current value"""
def __init__(self):
self.reset()
def reset(self):
self.val = 0
self.avg = 0
self.sum = 0
self.count = 0
def update(self, val, n=1):
self.val = val
self.sum += val * n
self.count += n
self.avg = self.sum / self.count
def load_vars_by_dict(executor, name_var_dict, main_program=None):
from paddle.fluid.framework import Program, Variable
from paddle.fluid import core
load_prog = Program()
load_block = load_prog.global_block()
if main_program is None:
main_program = fluid.default_main_program()
if not isinstance(main_program, Program):
raise TypeError("program should be as Program type or None")
for each_var_name in name_var_dict.keys():
assert isinstance(name_var_dict[each_var_name], Variable)
if name_var_dict[each_var_name].type == core.VarDesc.VarType.RAW:
continue
load_block.append_op(
type='load',
inputs={},
outputs={'Out': [name_var_dict[each_var_name]]},
attrs={'file_path': each_var_name})
executor.run(load_prog)
def get_model_id():
prefix = ''
if args.prefix is not None:
prefix = args.prefix + '-' # for some notes.
model_id = prefix + args.dataset + \
'-epo_' + str(args.num_epoch) + \
'-b_' + str(args.batch_size) + \
'-reg_' + str(args.delta_reg) + \
'-wd_' + str(args.wd_rate)
return model_id
def train():
dataset = args.dataset
image_shape = [3, 224, 224]
pretrained_model = args.pretrained_model
class_map_path = f'{global_data_path}/{dataset}/readable_label.txt'
if os.path.exists(class_map_path):
logger.info(
"The map of readable label and numerical label has been found!")
with open(class_map_path) as f:
label_dict = {}
strinfo = re.compile(r"\d+ ")
for item in f.readlines():
key = int(item.split(" ")[0])
value = [
strinfo.sub("", l).replace("\n", "")
for l in item.split(", ")
]
label_dict[key] = value[0]
assert os.path.isdir(
pretrained_model), "please load right pretrained model path for infer"
# data reader
batch_size = args.batch_size
reader_config = ReaderConfig(f'{global_data_path}/{dataset}', is_test=False)
reader = reader_config.get_reader()
train_reader = paddle.batch(
paddle.reader.shuffle(reader, buf_size=batch_size),
batch_size,
drop_last=True)
# model ops
image = fluid.data(
name='image', shape=[None] + image_shape, dtype='float32')
label = fluid.data(name='label', shape=[None, 1], dtype='int64')
model = ResNet101(is_test=False)
features, logits = model.net(
input=image, class_dim=reader_config.num_classes)
out = fluid.layers.softmax(logits)
# loss, metric
cost = fluid.layers.mean(fluid.layers.cross_entropy(out, label))
accuracy = fluid.layers.accuracy(input=out, label=label)
# delta regularization
# teacher model pre-trained on Imagenet, 1000 classes.
global_name = 't_'
t_model = ResNet101(is_test=True, global_name=global_name)
t_features, _ = t_model.net(input=image, class_dim=1000)
for f in t_features.keys():
t_features[f].stop_gradient = True
# delta loss. hard code for the layer name, which is just before global pooling.
delta_loss = fluid.layers.square(t_features['t_res5c.add.output.5.tmp_0'] -
features['res5c.add.output.5.tmp_0'])
delta_loss = fluid.layers.reduce_mean(delta_loss)
params = fluid.default_main_program().global_block().all_parameters()
parameters = []
for param in params:
if param.trainable:
if global_name in param.name:
print('\tfixing', param.name)
else:
print('\ttraining', param.name)
parameters.append(param.name)
# optimizer, with piecewise_decay learning rate.
total_steps = len(reader_config.image_paths) * args.num_epoch // batch_size
boundaries = [int(total_steps * 2 / 3)]
print('\ttotal learning steps:', total_steps)
print('\tlr decays at:', boundaries)
values = [0.01, 0.001]
optimizer = fluid.optimizer.Momentum(
learning_rate=fluid.layers.piecewise_decay(
boundaries=boundaries, values=values),
momentum=0.9,
parameter_list=parameters,
regularization=fluid.regularizer.L2Decay(args.wd_rate))
cur_lr = optimizer._global_learning_rate()
optimizer.minimize(
cost + args.delta_reg * delta_loss, parameter_list=parameters)
# data reader
feed_order = ['image', 'label']
# executor (session)
place = fluid.CUDAPlace(
args.use_cuda) if args.use_cuda >= 0 else fluid.CPUPlace()
exe = fluid.Executor(place)
# running
main_program = fluid.default_main_program()
start_program = fluid.default_startup_program()
feed_var_list_loop = [
main_program.global_block().var(var_name) for var_name in feed_order
]
feeder = fluid.DataFeeder(feed_list=feed_var_list_loop, place=place)
exe.run(start_program)
loading_parameters = {}
t_loading_parameters = {}
for p in main_program.all_parameters():
if 'fc' not in p.name:
if global_name in p.name:
new_name = os.path.join(pretrained_model,
p.name.split(global_name)[-1])
t_loading_parameters[new_name] = p
print(new_name, p.name)
else:
name = os.path.join(pretrained_model, p.name)
loading_parameters[name] = p
print(name, p.name)
else:
print(f'not loading {p.name}')
load_vars_by_dict(exe, loading_parameters, main_program=main_program)
load_vars_by_dict(exe, t_loading_parameters, main_program=main_program)
step = 0
# test_data = reader_creator_all_in_memory('./datasets/PetImages', is_test=True)
for e_id in range(args.num_epoch):
avg_delta_loss = AverageMeter()
avg_loss = AverageMeter()
avg_accuracy = AverageMeter()
batch_time = AverageMeter()
end = time.time()
for step_id, data_train in enumerate(train_reader()):
wrapped_results = exe.run(
main_program,
feed=feeder.feed(data_train),
fetch_list=[cost, accuracy, delta_loss, cur_lr])
# print(avg_loss_value[2])
batch_time.update(time.time() - end)
end = time.time()
avg_loss.update(wrapped_results[0][0], len(data_train))
avg_accuracy.update(wrapped_results[1][0], len(data_train))
avg_delta_loss.update(wrapped_results[2][0], len(data_train))
if step % 100 == 0:
print(
f"\tEpoch {e_id}, Global_Step {step}, Batch_Time {batch_time.avg: .2f},"
f" LR {wrapped_results[3][0]}, "
f"Loss {avg_loss.avg: .4f}, Acc {avg_accuracy.avg: .4f}, Delta_Loss {avg_delta_loss.avg: .4f}"
)
step += 1
if args.outdir is not None:
try:
os.makedirs(args.outdir, exist_ok=True)
fluid.io.save_params(
executor=exe, dirname=args.outdir + '/' + get_model_id())
except:
print('\t Not saving trained parameters.')
if e_id == args.num_epoch - 1:
print("kpis\ttrain_cost\t%f" % avg_loss.avg)
print("kpis\ttrain_acc\t%f" % avg_accuracy.avg)
def test():
image_shape = [3, 224, 224]
pretrained_model = args.outdir + '/' + get_model_id()
# data reader
batch_size = args.batch_size
reader_config = ReaderConfig(
f'{global_data_path}/{args.dataset}', is_test=True)
reader = reader_config.get_reader()
test_reader = paddle.batch(reader, batch_size)
# model ops
image = fluid.data(
name='image', shape=[None] + image_shape, dtype='float32')
label = fluid.data(name='label', shape=[None, 1], dtype='int64')
model = ResNet101(is_test=True)
_, logits = model.net(input=image, class_dim=reader_config.num_classes)
out = fluid.layers.softmax(logits)
# loss, metric
cost = fluid.layers.mean(fluid.layers.cross_entropy(out, label))
accuracy = fluid.layers.accuracy(input=out, label=label)
# data reader
feed_order = ['image', 'label']
# executor (session)
place = fluid.CUDAPlace(
args.use_cuda) if args.use_cuda >= 0 else fluid.CPUPlace()
exe = fluid.Executor(place)
# running
main_program = fluid.default_main_program()
start_program = fluid.default_startup_program()
feed_var_list_loop = [
main_program.global_block().var(var_name) for var_name in feed_order
]
feeder = fluid.DataFeeder(feed_list=feed_var_list_loop, place=place)
exe.run(start_program)
fluid.io.load_params(exe, pretrained_model)
step = 0
avg_loss = AverageMeter()
avg_accuracy = AverageMeter()
for step_id, data_train in enumerate(test_reader()):
avg_loss_value = exe.run(
main_program,
feed=feeder.feed(data_train),
fetch_list=[cost, accuracy])
avg_loss.update(avg_loss_value[0], len(data_train))
avg_accuracy.update(avg_loss_value[1], len(data_train))
if step_id % 10 == 0:
print("\nBatch %d, Loss %f, Acc %f" % (step_id, avg_loss.avg,
avg_accuracy.avg))
step += 1
print("test counts:", avg_loss.count)
print("test_cost\t%f" % avg_loss.avg)
print("test_acc\t%f" % avg_accuracy.avg)
if __name__ == '__main__':
print(args)
train()
test()
#copyright (c) 2019 PaddlePaddle Authors. All Rights Reserve.
#
#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 https://github.com/PaddlePaddle/models/blob/release/1.7/PaddleCV/image_classification/models/resnet.py.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import math
import paddle
import paddle.fluid as fluid
from paddle.fluid.param_attr import ParamAttr
__all__ = [
"ResNet", "ResNet18", "ResNet34", "ResNet50", "ResNet101", "ResNet152"
]
class ResNet():
def __init__(self, layers=50, is_test=True, global_name=''):
self.layers = layers
self.is_test = is_test
self.features = {}
self.global_name = global_name
def net(self, input, class_dim=1000, data_format="NCHW"):
layers = self.layers
supported_layers = [18, 34, 50, 101, 152]
assert layers in supported_layers, \
"supported layers are {} but input layer is {}".format(supported_layers, layers)
if layers == 18:
depth = [2, 2, 2, 2]
elif layers == 34 or layers == 50:
depth = [3, 4, 6, 3]
elif layers == 101:
depth = [3, 4, 23, 3]
elif layers == 152:
depth = [3, 8, 36, 3]
num_filters = [64, 128, 256, 512]
conv = self.conv_bn_layer(
input=input,
num_filters=64,
filter_size=7,
stride=2,
act='relu',
name="conv1",
data_format=data_format)
conv = fluid.layers.pool2d(
input=conv,
pool_size=3,
pool_stride=2,
pool_padding=1,
pool_type='max',
name=self.global_name + 'poo1',
data_format=data_format)
self.features[conv.name] = conv
if layers >= 50:
for block in range(len(depth)):
for i in range(depth[block]):
if layers in [101, 152] and block == 2:
if i == 0:
conv_name = "res" + str(block + 2) + "a"
else:
conv_name = "res" + str(block + 2) + "b" + str(i)
else:
conv_name = "res" + str(block + 2) + chr(97 + i)
conv = self.bottleneck_block(
input=conv,
num_filters=num_filters[block],
stride=2 if i == 0 and block != 0 else 1,
name=conv_name,
data_format=data_format)
self.features[conv.name] = conv
pool = fluid.layers.pool2d(
input=conv,
pool_type='avg',
global_pooling=True,
name=self.global_name + 'global_pooling',
data_format=data_format)
self.features[pool.name] = pool
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
out = fluid.layers.fc(
input=pool,
size=class_dim,
bias_attr=fluid.param_attr.ParamAttr(
name=self.global_name + 'fc_0.b_0'),
param_attr=fluid.param_attr.ParamAttr(
name=self.global_name + 'fc_0.w_0',
initializer=fluid.initializer.Uniform(-stdv, stdv)))
else:
for block in range(len(depth)):
for i in range(depth[block]):
conv_name = "res" + str(block + 2) + chr(97 + i)
conv = self.basic_block(
input=conv,
num_filters=num_filters[block],
stride=2 if i == 0 and block != 0 else 1,
is_first=block == i == 0,
name=conv_name,
data_format=data_format)
self.features[conv.name] = conv
pool = fluid.layers.pool2d(
input=conv,
pool_type='avg',
global_pooling=True,
name=self.global_name + 'global_pooling',
data_format=data_format)
self.features[pool.name] = pool
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
out = fluid.layers.fc(
input=pool,
size=class_dim,
bias_attr=fluid.param_attr.ParamAttr(
name=self.global_name + 'fc_0.b_0'),
param_attr=fluid.param_attr.ParamAttr(
name=self.global_name + 'fc_0.w_0',
initializer=fluid.initializer.Uniform(-stdv, stdv)))
return self.features, out
def conv_bn_layer(self,
input,
num_filters,
filter_size,
stride=1,
groups=1,
act=None,
name=None,
data_format='NCHW'):
conv = fluid.layers.conv2d(
input=input,
num_filters=num_filters,
filter_size=filter_size,
stride=stride,
padding=(filter_size - 1) // 2,
groups=groups,
act=None,
param_attr=ParamAttr(name=self.global_name + name + "_weights"),
bias_attr=False,
name=name + '.conv2d.output.1',
data_format=data_format)
if name == "conv1":
bn_name = "bn_" + name
else:
bn_name = "bn" + name[3:]
return fluid.layers.batch_norm(
input=conv,
act=act,
name=self.global_name + bn_name + '.output.1',
param_attr=ParamAttr(self.global_name + bn_name + '_scale'),
bias_attr=ParamAttr(self.global_name + bn_name + '_offset'),
moving_mean_name=self.global_name + bn_name + '_mean',
moving_variance_name=self.global_name + bn_name + '_variance',
data_layout=data_format,
use_global_stats=self.is_test)
def shortcut(self, input, ch_out, stride, is_first, name, data_format):
if data_format == 'NCHW':
ch_in = input.shape[1]
else:
ch_in = input.shape[-1]
if ch_in != ch_out or stride != 1 or is_first == True:
return self.conv_bn_layer(
input, ch_out, 1, stride, name=name, data_format=data_format)
else:
return input
def bottleneck_block(self, input, num_filters, stride, name, data_format):
conv0 = self.conv_bn_layer(
input=input,
num_filters=num_filters,
filter_size=1,
act='relu',
name=name + "_branch2a",
data_format=data_format)
conv1 = self.conv_bn_layer(
input=conv0,
num_filters=num_filters,
filter_size=3,
stride=stride,
act='relu',
name=name + "_branch2b",
data_format=data_format)
conv2 = self.conv_bn_layer(
input=conv1,
num_filters=num_filters * 4,
filter_size=1,
act=None,
name=name + "_branch2c",
data_format=data_format)
short = self.shortcut(
input,
num_filters * 4,
stride,
is_first=False,
name=name + "_branch1",
data_format=data_format)
return fluid.layers.elementwise_add(
x=short,
y=conv2,
act='relu',
name=self.global_name + name + ".add.output.5")
def basic_block(self, input, num_filters, stride, is_first, name,
data_format):
conv0 = self.conv_bn_layer(
input=input,
num_filters=num_filters,
filter_size=3,
act='relu',
stride=stride,
name=name + "_branch2a",
data_format=data_format)
conv1 = self.conv_bn_layer(
input=conv0,
num_filters=num_filters,
filter_size=3,
act=None,
name=name + "_branch2b",
data_format=data_format)
short = self.shortcut(
input,
num_filters,
stride,
is_first,
name=name + "_branch1",
data_format=data_format)
return fluid.layers.elementwise_add(
x=short,
y=conv1,
act='relu',
name=self.global_name + name + ".add.output.5")
def ResNet18(is_test=True, global_name=''):
model = ResNet(layers=18, is_test=is_test, global_name=global_name)
return model
def ResNet34(is_test=True, global_name=''):
model = ResNet(layers=34, is_test=is_test, global_name=global_name)
return model
def ResNet50(is_test=True, global_name=''):
model = ResNet(layers=50, is_test=is_test, global_name=global_name)
return model
def ResNet101(is_test=True, global_name=''):
model = ResNet(layers=101, is_test=is_test, global_name=global_name)
return model
def ResNet152(is_test=True, global_name=''):
model = ResNet(layers=152, is_test=is_test, global_name=global_name)
return model
#copyright (c) 2019 PaddlePaddle Authors. All Rights Reserve.
#
#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 https://github.com/PaddlePaddle/models/blob/release/1.7/PaddleCV/image_classification/models/resnet_vc.py.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import math
import paddle
import paddle.fluid as fluid
from paddle.fluid.param_attr import ParamAttr
__all__ = ["ResNet", "ResNet50_vc", "ResNet101_vc", "ResNet152_vc"]
train_parameters = {
"input_size": [3, 224, 224],
"input_mean": [0.485, 0.456, 0.406],
"input_std": [0.229, 0.224, 0.225],
"learning_strategy": {
"name": "piecewise_decay",
"batch_size": 256,
"epochs": [30, 60, 90],
"steps": [0.1, 0.01, 0.001, 0.0001]
}
}
class ResNet():
def __init__(self, layers=50, is_test=False, global_name=''):
self.params = train_parameters
self.layers = layers
self.is_test = is_test
self.features = {}
self.global_name = global_name
def net(self, input, class_dim=1000):
layers = self.layers
supported_layers = [50, 101, 152]
assert layers in supported_layers, \
"supported layers are {} but input layer is {}".format(supported_layers, layers)
if layers == 50:
depth = [3, 4, 6, 3]
elif layers == 101:
depth = [3, 4, 23, 3]
elif layers == 152:
depth = [3, 8, 36, 3]
num_filters = [64, 128, 256, 512]
conv = self.conv_bn_layer(
input=input,
num_filters=32,
filter_size=3,
stride=2,
act='relu',
name='conv1_1')
conv = self.conv_bn_layer(
input=conv,
num_filters=32,
filter_size=3,
stride=1,
act='relu',
name='conv1_2')
conv = self.conv_bn_layer(
input=conv,
num_filters=64,
filter_size=3,
stride=1,
act='relu',
name='conv1_3')
conv = fluid.layers.pool2d(
input=conv,
pool_size=3,
pool_stride=2,
pool_padding=1,
pool_type='max',
name=self.global_name + 'poo1')
self.features[conv.name] = conv
for block in range(len(depth)):
for i in range(depth[block]):
if layers in [101, 152] and block == 2:
if i == 0:
conv_name = "res" + str(block + 2) + "a"
else:
conv_name = "res" + str(block + 2) + "b" + str(i)
else:
conv_name = "res" + str(block + 2) + chr(97 + i)
conv = self.bottleneck_block(
input=conv,
num_filters=num_filters[block],
stride=2 if i == 0 and block != 0 else 1,
name=conv_name)
self.features[conv.name] = conv
pool = fluid.layers.pool2d(
input=conv,
pool_type='avg',
global_pooling=True,
name=self.global_name + 'global_pooling')
self.features[pool.name] = pool
stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
out = fluid.layers.fc(
input=pool,
size=class_dim,
bias_attr=fluid.param_attr.ParamAttr(
name=self.global_name + 'fc_0.b_0'),
param_attr=fluid.param_attr.ParamAttr(
name=self.global_name + 'fc_0.w_0',
initializer=fluid.initializer.Uniform(-stdv, stdv)))
return self.features, out
def conv_bn_layer(self,
input,
num_filters,
filter_size,
stride=1,
groups=1,
act=None,
name=None):
conv = fluid.layers.conv2d(
input=input,
num_filters=num_filters,
filter_size=filter_size,
stride=stride,
padding=(filter_size - 1) // 2,
groups=groups,
act=None,
param_attr=ParamAttr(name=self.global_name + name + "_weights"),
bias_attr=False,
name=self.global_name + name + '.conv2d.output.1')
if name == "conv1":
bn_name = "bn_" + name
else:
bn_name = "bn" + name[3:]
return fluid.layers.batch_norm(
input=conv,
act=act,
name=self.global_name + bn_name + '.output.1',
param_attr=ParamAttr(self.global_name + bn_name + '_scale'),
bias_attr=ParamAttr(self.global_name + bn_name + '_offset'),
moving_mean_name=self.global_name + bn_name + '_mean',
moving_variance_name=self.global_name + bn_name + '_variance',
use_global_stats=self.is_test)
def shortcut(self, input, ch_out, stride, name):
ch_in = input.shape[1]
if ch_in != ch_out or stride != 1:
return self.conv_bn_layer(input, ch_out, 1, stride, name=name)
else:
return input
def bottleneck_block(self, input, num_filters, stride, name):
conv0 = self.conv_bn_layer(
input=input,
num_filters=num_filters,
filter_size=1,
act='relu',
name=name + "_branch2a")
conv1 = self.conv_bn_layer(
input=conv0,
num_filters=num_filters,
filter_size=3,
stride=stride,
act='relu',
name=name + "_branch2b")
conv2 = self.conv_bn_layer(
input=conv1,
num_filters=num_filters * 4,
filter_size=1,
act=None,
name=name + "_branch2c")
short = self.shortcut(
input, num_filters * 4, stride, name=name + "_branch1")
return fluid.layers.elementwise_add(
x=short,
y=conv2,
act='relu',
name=self.global_name + name + ".add.output.5")
def ResNet50_vc(is_test=True, global_name=''):
model = ResNet(layers=50, is_test=is_test, global_name=global_name)
return model
def ResNet101_vc(is_test=True, global_name=''):
model = ResNet(layers=101, is_test=is_test, global_name=global_name)
return model
def ResNet152_vc(is_test=True, global_name=''):
model = ResNet(layers=152, is_test=is_test, global_name=global_name)
return model
...@@ -2,78 +2,74 @@ ...@@ -2,78 +2,74 @@
目前PaddleHub有以下任务示例: 目前PaddleHub有以下任务示例:
>* 图像分类 * [口罩检测](./mask_detection)
提供了基于完整的口罩人脸检测及分类的模型搭建的完整的视频级别Demo,同时提供基于飞桨高性能预测库的C++和Python部署方案。
>* 中文词法分析 * [图像分类](./image_classification)
该样例展示了PaddleHub如何将ResNet50、ResNet101、ResNet152、MobileNet、NasNet以及PNasNet作为预训练模型在Flowers、DogCat、Indoor67、Food101、StanfordDogs等数据集上进行图像分类的FineTune和预测。
>* 情感分析 * [中文词法分析](./lac)
该样例展示了PaddleHub如何利用中文词法分析LAC进行预测。
>* 序列标注 * [情感分析](./senta)
该样例展示了PaddleHub如何利用中文情感分析模型Senta进行FineTune和预测。
>* 目标检测 * [序列标注](./sequence_labeling)
该样例展示了PaddleHub如何将ERNIE/BERT等Transformer类模型作为预训练模型在MSRA_NER数据集上完成序列标注的FineTune和预测。
>* 文本分类 * [目标检测](./ssd)
该样例展示了PaddleHub如何将SSD作为预训练模型在PascalVOC数据集上完成目标检测的预测。
>* 多标签分类 * [文本分类](./text_classification)
该样例展示了PaddleHub如何将ERNIE/BERT等Transformer类模型作为预训练模型在GLUE、ChnSentiCorp等数据集上完成文本分类的FineTune和预测。
**同时,该样例还展示了如何将一个Fine-tune保存的模型转化成PaddleHub Module。** 请确认转化时,使用的PaddleHub为1.6.0以上版本。
>* 回归任务 * [多标签分类](./multi_label_classification)
该样例展示了PaddleHub如何将BERT作为预训练模型在Toxic数据集上完成多标签分类的FineTune和预测。
>* 阅读理解 * [回归任务](./regression)
该样例展示了PaddleHub如何将BERT作为预训练模型在GLUE-STSB数据集上完成回归任务的FineTune和预测。
>* 检索式问答任务 * [阅读理解](./reading_comprehension)
该样例展示了PaddleHub如何将BERT作为预训练模型在SQAD数据集上完成阅读理解的FineTune和预测。
>* 句子语义相似度计算 * [检索式问答任务](./qa_classfication)
该样例展示了PaddleHub如何将ERNIE和BERT作为预训练模型在NLPCC-DBQA等数据集上完成检索式问答任务的FineTune和预测。
## 图像分类 * [句子语义相似度计算](./sentence_similarity)
该样例展示了PaddleHub如何将word2vec_skipgram用于计算两个文本语义相似度。
该样例展示了PaddleHub如何将ResNet50、ResNet101、ResNet152、MobileNet、NasNet以及PNasNet作为预训练模型在Flowers、DogCat、Indoor67、Food101、StanfordDogs等数据集上进行图像分类的FineTune和预测。 * [超参优化AutoDL Finetuner使用](./autofinetune)
该样例展示了PaddleHub超参优化AutoDL Finetuner如何使用,给出了自动搜素图像分类/文本分类任务的较佳超参数示例。
## 中文词法分析 * [服务化部署Hub Serving使用](./serving)
该样例文件夹下展示了服务化部署Hub Serving如何使用,将PaddleHub支持的可预测Module如何服务化部署。
该样例展示了PaddleHub如何利用中文词法分析LAC进行预测。 * [预训练模型转化成PaddleHub Module](./senta_module_sample)
该样例展示了如何将一个预训练模型转化成PaddleHub Module形式,使得可以通过`hub.Module(name="module_name")`实现一键加载。
请确认转化时,使用的PaddleHub为1.6.0以上版本。
## 情感分析 **NOTE:**
以上任务示例均是利用PaddleHub提供的数据集,若您想在自定义数据集上完成相应任务,请查看[PaddleHub适配自定义数据完成Fine-tune](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)
该样例展示了PaddleHub如何利用中文情感分析模型Senta进行FineTune和预测。 ## 在线体验
## 序列标注 我们在AI Studio上提供了IPython NoteBook形式的demo,您可以直接在平台上在线体验,链接如下:
该样例展示了PaddleHub如何将ERNIE和BERT作为预训练模型在MSRA_NER数据集上 |预训练模型|任务类型|数据集|AIStudio链接|备注|
完成序列标注的FineTune和预测。 |-|-|-|-|-|
|ResNet|图像分类|猫狗数据集DogCat|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/147010)||
|ERNIE|文本分类|中文情感分类数据集ChnSentiCorp|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/147006)||
|ERNIE|文本分类|中文新闻分类数据集THUNEWS|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/221999)|本教程讲述了如何将自定义数据集加载,并利用Fine-tune API完成文本分类迁移学习。|
|ERNIE|序列标注|中文序列标注数据集MSRA_NER|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/147009)||
|ERNIE|序列标注|中文快递单数据集Express|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/184200)|本教程讲述了如何将自定义数据集加载,并利用Fine-tune API完成序列标注迁移学习。|
|ERNIE Tiny|文本分类|中文情感分类数据集ChnSentiCorp|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/186443)||
|Senta|文本分类|中文情感分类数据集ChnSentiCorp|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/216846)|本教程讲述了任何利用Senta和Fine-tune API完成情感分类迁移学习。|
|Senta|情感分析预测|N/A|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/215814)||
|LAC|词法分析|N/A|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/215711)||
|Ultra-Light-Fast-Generic-Face-Detector-1MB|人脸检测|N/A|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/215962)||
## 目标检测
该样例展示了PaddleHub如何将SSD作为预训练模型在PascalVOC数据集上 ## 超参优化AutoDL Finetuner
完成目标检测的预测。
## 文本分类 PaddleHub还提供了超参优化(Hyperparameter Tuning)功能, 自动搜索最优模型超参得到更好的模型效果。详细信息参见[AutoDL Finetuner超参优化功能教程](../docs/tutorial/autofinetune.md)
该样例展示了PaddleHub
>* 如何将ERNIE和BERT作为预训练模型在ChnSentiCorp、LCQMC和NLPCC-DBQA等数据集上完成文本分类的FineTune和预测。
>* 如何将ELMo预训练得到的中文word embedding加载,完成在ChnSentiCorp数据集上文本分类的FineTune和预测。
## 多标签分类
该样例展示了PaddleHub如何将BERT作为预训练模型在Toxic数据集上完成多标签分类的FineTune和预测。
## 回归任务
该样例展示了PaddleHub如何将BERT作为预训练模型在GLUE-STSB数据集上完成回归任务的FineTune和预测。
## 阅读理解
该样例展示了PaddleHub如何将BERT作为预训练模型在SQAD数据集上完成阅读理解的FineTune和预测。
## 检索式问答任务
该样例展示了PaddleHub如何将ERNIE和BERT作为预训练模型在NLPCC-DBQA等数据集上完成检索式问答任务的FineTune和预测。
## 句子语义相似度计算
该样例展示了PaddleHub如何将word2vec_skipgram用于计算两个文本语义相似度。
## 模型服务化
展示了PaddleHub-Serving如何利用模型进行服务化部署,主要包括模型预测服务化和Bert-as-Service服务化。
**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)
# PaddleHub超参优化——图像分类
**确认安装PaddleHub版本在1.3.0以上, 同时PaddleHub AutoDL Finetuner功能要求至少有一张GPU显卡可用。**
本示例展示如何利用PaddleHub超参优化AutoDL Finetuner,得到一个效果较佳的超参数组合
使用PaddleHub AutoDL Finetuner需要准备两个指定格式的文件:待优化的超参数信息yaml文件hparam.yaml和需要Fine-tune的python脚本train.py
以Fine-tune图像分类任务为例, 其中:
## hparam.yaml
hparam给出待搜索的超参名字、类型(int或者float)、搜索范围等信息。
通过这些信息构建了一个超参空间,PaddleHub将在这个空间内进行超参数的搜索,将搜索到的超参传入train.py获得评估效果,根据评估效果自动调整超参搜索方向,直到满足搜索次数。
本示例中待优化超参数为learning_rate和batch_size。
## img_cls.py
以mobilenet为预训练模型,在flowers数据集上进行Fine-tune。
## 如何开始超参优化
在完成安装PaddlePaddle与PaddleHub后,通过执行脚本`sh run_autofinetune.sh`即可开始使用超参优化功能。
`NOTE`: 关于PaddleHub超参优化详情参考[教程](https://github.com/PaddlePaddle/PaddleHub/blob/release/v1.2/tutorial/autofinetune.md)
# PaddleHub超参优化——图像分类
**确认安装PaddleHub版本在1.3.0以上, 同时PaddleHub AutoDL Finetuner功能要求至少有一张GPU显卡可用。**
本示例展示如何利用PaddleHub超参优化AutoDL Finetuner,得到一个效果较佳的超参数组合。
每次执行AutoDL Finetuner,用户只需要定义搜索空间,改动几行代码,就能利用PaddleHub搜索最好的超参组合。 只需要两步即可完成:
* 定义搜索空间:AutoDL Finetuner会根据搜索空间来取样生成参数和网络架构。搜索空间通过YAML文件来定义。
* 改动模型代码:需要首先定义参数组,并更新模型代码。
## Step1:定义搜索空间
AutoDL Finetuner会根据搜索空间来取样生成参数和网络架构。搜索空间通过YAML文件来定义。
要定义搜索空间,需要定义变量名称、类型及其搜索范围。通过这些信息构建了一个超参空间,
PaddleHub将在这个空间内进行超参数的搜索,将搜索到的超参传入train.py获得评估效果,根据评估效果自动调整超参搜索方向,直到满足搜索次数。
以Fine-tune图像分类任务为例, 以下是待优化超参数的yaml文件hparam.yaml,包含需要搜素的超参名字、类型、范围等信息。目前参数搜索类型只支持float和int类型。
```
param_list:
- name : learning_rate
init_value : 0.001
type : float
lower_than : 0.05
greater_than : 0.00005
- name : batch_size
init_value : 12
type : int
lower_than : 20
greater_than : 10
```
## Step2:改动模型代码
img_cls.py以mobilenet为预训练模型,在flowers数据集上进行Fine-tune。PaddleHub如何完成Finetune可以参考[图像分类迁移学习示例](../image_classification)
* import paddlehub
在img_cls.py加上`import paddlehub as hub`
* 从AutoDL Finetuner获得参数值
1. img_cls.py的选项参数须包含待优化超参数,需要将超参以argparser的方式写在其中,待搜索超参数选项名字和yaml文件中的超参数名字保持一致。
2. img_cls.py须包含选项参数saved_params_dir,优化后的参数将会保存到该路径下。
3. 超参评估策略选择PopulationBased时,img_cls.py须包含选项参数model_path,自动从model_path指定的路径恢复模型
* 返回配置的最终效果
img_cls.py须反馈模型的评价效果(建议使用验证集或者测试集上的评价效果),通过调用`report_final_result`接口反馈,如
```python
hub.report_final_result(eval_avg_score["acc"])
```
**NOTE:** 输出的评价效果取值范围应为`(-∞, 1]`,取值越高,表示效果越好。
## 启动AutoDL Finetuner
在完成安装PaddlePaddle与PaddleHub后,通过执行脚本`sh run_autofinetune.sh`即可开始使用超参优化功能。
**NOTE:** 关于PaddleHub超参优化详情参考[教程](../../docs/tutorial/autofinetune.md)
...@@ -4,7 +4,6 @@ import os ...@@ -4,7 +4,6 @@ import os
import ast import ast
import shutil import shutil
import paddle.fluid as fluid
import paddlehub as hub import paddlehub as hub
from paddlehub.common.logger import logger from paddlehub.common.logger import logger
...@@ -19,7 +18,7 @@ parser.add_argument( ...@@ -19,7 +18,7 @@ parser.add_argument(
default="mobilenet", default="mobilenet",
help="Module used as feature extractor.") help="Module used as feature extractor.")
# the name of hyperparameters to be searched should keep with hparam.py # the name of hyper-parameters to be searched should keep with hparam.py
parser.add_argument( parser.add_argument(
"--batch_size", "--batch_size",
type=int, type=int,
...@@ -28,7 +27,7 @@ parser.add_argument( ...@@ -28,7 +27,7 @@ parser.add_argument(
parser.add_argument( parser.add_argument(
"--learning_rate", type=float, default=1e-4, help="learning_rate.") "--learning_rate", type=float, default=1e-4, help="learning_rate.")
# saved_params_dir and model_path are needed by auto finetune # saved_params_dir and model_path are needed by auto fine-tune
parser.add_argument( parser.add_argument(
"--saved_params_dir", "--saved_params_dir",
type=str, type=str,
...@@ -58,7 +57,6 @@ def is_path_valid(path): ...@@ -58,7 +57,6 @@ def is_path_valid(path):
def finetune(args): def finetune(args):
# Load Paddlehub pretrained model, default as mobilenet # Load Paddlehub pretrained model, default as mobilenet
module = hub.Module(name=args.module) module = hub.Module(name=args.module)
input_dict, output_dict, program = module.context(trainable=True) input_dict, output_dict, program = module.context(trainable=True)
...@@ -78,7 +76,7 @@ def finetune(args): ...@@ -78,7 +76,7 @@ def finetune(args):
img = input_dict["image"] img = input_dict["image"]
feed_list = [img.name] feed_list = [img.name]
# Select finetune strategy, setup config and finetune # Select fine-tune strategy, setup config and fine-tune
strategy = hub.DefaultFinetuneStrategy(learning_rate=args.learning_rate) strategy = hub.DefaultFinetuneStrategy(learning_rate=args.learning_rate)
config = hub.RunConfig( config = hub.RunConfig(
use_cuda=True, use_cuda=True,
...@@ -102,7 +100,7 @@ def finetune(args): ...@@ -102,7 +100,7 @@ def finetune(args):
task.load_parameters(args.model_path) task.load_parameters(args.model_path)
logger.info("PaddleHub has loaded model from %s" % args.model_path) logger.info("PaddleHub has loaded model from %s" % args.model_path)
# Finetune by PaddleHub's API # Fine-tune by PaddleHub's API
task.finetune() task.finetune()
# Evaluate by PaddleHub's API # Evaluate by PaddleHub's API
run_states = task.eval() run_states = task.eval()
...@@ -116,7 +114,7 @@ def finetune(args): ...@@ -116,7 +114,7 @@ def finetune(args):
shutil.copytree(best_model_dir, args.saved_params_dir) shutil.copytree(best_model_dir, args.saved_params_dir)
shutil.rmtree(config.checkpoint_dir) shutil.rmtree(config.checkpoint_dir)
# acc on dev will be used by auto finetune # acc on dev will be used by auto fine-tune
hub.report_final_result(eval_avg_score["acc"]) hub.report_final_result(eval_avg_score["acc"])
......
# PaddleHub超参优化——文本分类
**确认安装PaddleHub版本在1.3.0以上, 同时PaddleHub AutoDL Finetuner功能要求至少有一张GPU显卡可用。**
本示例展示如何利用PaddleHub超参优化AutoDL Finetuner,得到一个效果较佳的超参数组合。
每次执行AutoDL Finetuner,用户只需要定义搜索空间,改动几行代码,就能利用PaddleHub搜索最好的超参组合。 只需要两步即可完成:
* 定义搜索空间:AutoDL Finetuner会根据搜索空间来取样生成参数和网络架构。搜索空间通过YAML文件来定义。
* 改动模型代码:需要首先定义参数组,并更新模型代码。
## Step1:定义搜索空间
AutoDL Finetuner会根据搜索空间来取样生成参数和网络架构。搜索空间通过YAML文件来定义。
要定义搜索空间,需要定义变量名称、类型及其搜索范围。通过这些信息构建了一个超参空间,
PaddleHub将在这个空间内进行超参数的搜索,将搜索到的超参传入train.py获得评估效果,根据评估效果自动调整超参搜索方向,直到满足搜索次数。
以Fine-tune文本分类任务为例, 以下是待优化超参数的yaml文件hparam.yaml,包含需要搜素的超参名字、类型、范围等信息。目前参数搜索类型只支持float和int类型。
```
param_list:
- name : learning_rate
init_value : 0.001
type : float
lower_than : 0.05
greater_than : 0.000005
- name : weight_decay
init_value : 0.1
type : float
lower_than : 1
greater_than : 0.0
- name : batch_size
init_value : 32
type : int
lower_than : 40
greater_than : 30
- name : warmup_prop
init_value : 0.1
type : float
lower_than : 0.2
greater_than : 0.0
```
## Step2:改动模型代码
text_cls.py以ernie为预训练模型,在ChnSentiCorp数据集上进行Fine-tune。PaddleHub如何完成Finetune可以参考[文本分类迁移学习示例](../text_classification)
* import paddlehub
在text_cls.py加上`import paddlehub as hub`
* 从AutoDL Finetuner获得参数值
1. text_cls.py的选项参数须包含待优化超参数,需要将超参以argparser的方式写在其中,待搜索超参数选项名字和yaml文件中的超参数名字保持一致。
2. text_cls.py须包含选项参数saved_params_dir,优化后的参数将会保存到该路径下。
3. 超参评估策略选择PopulationBased时,text_cls.py须包含选项参数model_path,自动从model_path指定的路径恢复模型
* 返回配置的最终效果
text_cls.py须反馈模型的评价效果(建议使用验证集或者测试集上的评价效果),通过调用`report_final_result`接口反馈,如
```python
hub.report_final_result(eval_avg_score["acc"])
```
**NOTE:** 输出的评价效果取值范围应为`(-∞, 1]`,取值越高,表示效果越好。
## 启动AutoDL Finetuner
在完成安装PaddlePaddle与PaddleHub后,通过执行脚本`sh run_autofinetune.sh`即可开始使用超参优化功能。
**NOTE:** 关于PaddleHub超参优化详情参考[教程](../../docs/tutorial/autofinetune.md)
param_list:
- name : learning_rate
init_value : 0.001
type : float
lower_than : 0.05
greater_than : 0.000005
- name : weight_decay
init_value : 0.1
type : float
lower_than : 1
greater_than : 0.0
- name : batch_size
init_value : 32
type : int
lower_than : 40
greater_than : 30
- name : warmup_prop
init_value : 0.1
type : float
lower_than : 0.2
greater_than : 0.0
OUTPUT=result
hub autofinetune text_cls.py \
--param_file=hparam.yaml \
--gpu=0 \
--popsize=15 \
--round=10 \
--output_dir=${OUTPUT} \
--evaluator=fulltrail \
--tuning_strategy=pshe2
# PaddleHub 超参优化(AutoDL Finetuner)——NLP情感分类任务
使用PaddleHub AutoDL Finetuner需要准备两个指定格式的文件:待优化的超参数信息yaml文件hparam.yaml和需要Fine-tune的python脚本train.py
以Fine-tune中文情感分类任务为例,展示如何利用PaddleHub AutoDL Finetuner进行超参优化。
以下是待优化超参数的yaml文件hparam.yaml,包含需要搜索的超参名字、类型、范围等信息。其中类型只支持float和int
```
param_list:
- name : learning_rate
init_value : 0.001
type : float
lower_than : 0.05
greater_than : 0.000005
- name : weight_decay
init_value : 0.1
type : float
lower_than : 1
greater_than : 0.0
- name : batch_size
init_value : 32
type : int
lower_than : 40
greater_than : 30
- name : warmup_prop
init_value : 0.1
type : float
lower_than : 0.2
greater_than : 0.0
```
以下是中文情感分类的`train.py`
```python
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
import argparse import argparse
import ast import ast
import shutil
import paddle.fluid as fluid
import paddlehub as hub import paddlehub as hub
import os import os
from paddlehub.common.logger import logger from paddlehub.common.logger import logger
...@@ -47,18 +13,34 @@ from paddlehub.common.logger import logger ...@@ -47,18 +13,34 @@ from paddlehub.common.logger import logger
parser = argparse.ArgumentParser(__doc__) parser = argparse.ArgumentParser(__doc__)
parser.add_argument("--epochs", type=int, default=3, help="epochs.") parser.add_argument("--epochs", type=int, default=3, help="epochs.")
# the name of hyperparameters to be searched should keep with hparam.py # the name of hyper-parameters to be searched should keep with hparam.py
parser.add_argument("--batch_size", type=int, default=32, help="batch_size.") parser.add_argument("--batch_size", type=int, default=32, help="batch_size.")
parser.add_argument("--learning_rate", type=float, default=5e-5, help="learning_rate.") parser.add_argument(
parser.add_argument("--warmup_prop", type=float, default=0.1, help="warmup_prop.") "--learning_rate", type=float, default=5e-5, help="learning_rate.")
parser.add_argument("--weight_decay", type=float, default=0.01, help="weight_decay.") parser.add_argument(
"--warmup_prop", type=float, default=0.1, help="warmup_prop.")
parser.add_argument("--max_seq_len", type=int, default=128, help="Number of words of the longest seqence.") parser.add_argument(
parser.add_argument("--checkpoint_dir", type=str, default=None, help="Directory to model checkpoint") "--weight_decay", type=float, default=0.01, help="weight_decay.")
# saved_params_dir and model_path are needed by auto finetune parser.add_argument(
parser.add_argument("--saved_params_dir", type=str, default="", help="Directory for saving model during ") "--max_seq_len",
parser.add_argument("--model_path", type=str, default="", help="load model path") type=int,
default=128,
help="Number of words of the longest seqence.")
parser.add_argument(
"--checkpoint_dir",
type=str,
default=None,
help="Directory to model checkpoint")
# saved_params_dir and model_path are needed by auto fine-tune
parser.add_argument(
"--saved_params_dir",
type=str,
default="",
help="Directory for saving model during ")
parser.add_argument(
"--model_path", type=str, default="", help="load model path")
args = parser.parse_args() args = parser.parse_args()
...@@ -71,6 +53,7 @@ def is_path_valid(path): ...@@ -71,6 +53,7 @@ def is_path_valid(path):
os.mkdir(dirname) os.mkdir(dirname)
return True return True
if __name__ == '__main__': if __name__ == '__main__':
# Load Paddlehub ERNIE pretrained model # Load Paddlehub ERNIE pretrained model
module = hub.Module(name="ernie") module = hub.Module(name="ernie")
...@@ -99,14 +82,14 @@ if __name__ == '__main__': ...@@ -99,14 +82,14 @@ if __name__ == '__main__':
inputs["input_mask"].name, inputs["input_mask"].name,
] ]
# Select finetune strategy, setup config and finetune # Select fine-tune strategy, setup config and fine-tune
strategy = hub.AdamWeightDecayStrategy( strategy = hub.AdamWeightDecayStrategy(
warmup_proportion=args.warmup_prop, warmup_proportion=args.warmup_prop,
learning_rate=args.learning_rate, learning_rate=args.learning_rate,
weight_decay=args.weight_decay, weight_decay=args.weight_decay,
lr_scheduler="linear_decay") lr_scheduler="linear_decay")
# Setup runing config for PaddleHub Finetune API # Setup RunConfig for PaddleHub Fine-tune API
config = hub.RunConfig( config = hub.RunConfig(
checkpoint_dir=args.checkpoint_dir, checkpoint_dir=args.checkpoint_dir,
use_cuda=True, use_cuda=True,
...@@ -115,7 +98,7 @@ if __name__ == '__main__': ...@@ -115,7 +98,7 @@ if __name__ == '__main__':
enable_memory_optim=True, enable_memory_optim=True,
strategy=strategy) strategy=strategy)
# Define a classfication finetune task by PaddleHub's API # Define a classfication fine-tune task by PaddleHub's API
cls_task = hub.TextClassifierTask( cls_task = hub.TextClassifierTask(
data_reader=reader, data_reader=reader,
feature=pooled_output, feature=pooled_output,
...@@ -133,7 +116,8 @@ if __name__ == '__main__': ...@@ -133,7 +116,8 @@ if __name__ == '__main__':
cls_task.finetune() cls_task.finetune()
run_states = cls_task.eval() run_states = cls_task.eval()
eval_avg_score, eval_avg_loss, eval_run_speed = cls_task._calculate_metrics(run_states) eval_avg_score, eval_avg_loss, eval_run_speed = cls_task._calculate_metrics(
run_states)
# Move ckpt/best_model to the defined saved parameters directory # Move ckpt/best_model to the defined saved parameters directory
best_model_dir = os.path.join(config.checkpoint_dir, "best_model") best_model_dir = os.path.join(config.checkpoint_dir, "best_model")
...@@ -141,6 +125,5 @@ if __name__ == '__main__': ...@@ -141,6 +125,5 @@ if __name__ == '__main__':
shutil.copytree(best_model_dir, args.saved_params_dir) shutil.copytree(best_model_dir, args.saved_params_dir)
shutil.rmtree(config.checkpoint_dir) shutil.rmtree(config.checkpoint_dir)
# acc on dev will be used by auto finetune # acc on dev will be used by auto fine-tune
hub.report_final_result(eval_avg_score["acc"]) hub.report_final_result(eval_avg_score["acc"])
```
# PaddleHub 文本分类
本示例将展示如何使用PaddleHub Finetune API以及加载ELMo预训练中文word embedding在中文情感分析数据集ChnSentiCorp上完成分类任务。
## 如何开始Finetune
在完成安装PaddlePaddle与PaddleHub后,通过执行脚本`sh run_elmo_finetune.sh`即可开始使用ELMo对ChnSentiCorp数据集进行Finetune。
其中脚本参数说明如下:
```bash
# 模型相关
--batch_size: 批处理大小,请结合显存情况进行调整,若出现显存不足,请适当调低这一参数use
--use_gpu: 是否使用GPU进行FineTune,默认为True
--learning_rate: Finetune的最大学习率
--weight_decay: 控制正则项力度的参数,用于防止过拟合,默认为0.01
--warmup_proportion: 学习率warmup策略的比例,如果0.1,则学习率会在前10%训练step的过程中从0慢慢增长到learning_rate, 而后再缓慢衰减,默认为0
--num_epoch: Finetune迭代的轮数
# 任务相关
--checkpoint_dir: 模型保存路径,PaddleHub会自动保存验证集上表现最好的模型
```
## 代码步骤
使用PaddleHub Finetune API进行Finetune可以分为4个步骤
### Step1: 加载预训练模型
```python
module = hub.Module(name="elmo")
inputs, outputs, program = module.context(trainable=True)
```
### Step2: 准备数据集并使用LACClassifyReader读取数据
```python
dataset = hub.dataset.ChnSentiCorp()
reader = hub.reader.LACClassifyReader(
dataset=dataset,
vocab_path=module.get_vocab_path())
```
其中数据集的准备代码可以参考 [chnsenticorp.py](https://github.com/PaddlePaddle/PaddleHub/blob/release/v1.2/paddlehub/dataset/chnsenticorp.py)
`hub.dataset.ChnSentiCorp()` 会自动从网络下载数据集并解压到用户目录下`$HOME/.paddlehub/dataset`目录
`module.get_vaocab_path()` 会返回预训练模型对应的词表
LACClassifyReader中的`data_generator`会自动按照模型对应词表对数据进行切词,以迭代器的方式返回ELMo所需要的Tensor格式,包括`word_ids`.
### Step3:选择优化策略和运行配置
```python
strategy = hub.AdamWeightDecayStrategy(
learning_rate=5e-5,
weight_decay=0.01,
warmup_proportion=0.0,
lr_scheduler="linear_decay",
)
config = hub.RunConfig(use_cuda=True, use_data_parallel=True, use_pyreader=False, num_epoch=3, batch_size=32, strategy=strategy)
```
#### 优化策略
针对ERNIE与BERT类任务,PaddleHub封装了适合这一任务的迁移学习优化策略`AdamWeightDecayStrategy`
* `learning_rate`: Finetune过程中的最大学习率;
* `weight_decay`: 模型的正则项参数,默认0.01,如果模型有过拟合倾向,可适当调高这一参数;
* `warmup_proportion`: 如果warmup_proportion>0, 例如0.1, 则学习率会在前10%的steps中线性增长至最高值learning_rate;
* `lr_scheduler`: 有两种策略可选(1) `linear_decay`策略学习率会在最高点后以线性方式衰减; `noam_decay`策略学习率会在最高点以多项式形式衰减;
#### 运行配置
`RunConfig` 主要控制Finetune的训练,包含以下可控制的参数:
* `log_interval`: 进度日志打印间隔,默认每10个step打印一次
* `eval_interval`: 模型评估的间隔,默认每100个step评估一次验证集
* `save_ckpt_interval`: 模型保存间隔,请根据任务大小配置,默认只保存验证集效果最好的模型和训练结束的模型
* `use_cuda`: 是否使用GPU训练,默认为False
* `use_data_parallel`: 是否使用并行计算,默认False。打开该功能依赖nccl库
* `use_pyreader`: 是否使用pyreader,默认False
* `checkpoint_dir`: 模型checkpoint保存路径, 若用户没有指定,程序会自动生成
* `num_epoch`: finetune的轮数
* `batch_size`: 训练的批大小,如果使用GPU,请根据实际情况调整batch_size
* `enable_memory_optim`: 是否使用内存优化, 默认为True
* `strategy`: Finetune优化策略
**Note**: 当使用LACClassifyReader时,use_pyreader应该为False。
### Step4: 构建网络并创建分类迁移任务进行Finetune
有了合适的预训练模型和准备要迁移的数据集后,我们开始组建一个Task。
>* 获取module的上下文环境,包括输入和输出的变量,以及Paddle Program;
>* 从输出变量中找到输入单词对应的elmo_embedding, 并拼接上随机初始化word embedding;
>* 在拼接embedding输入gru网络,进行文本分类,生成Task;
```python
word_ids = inputs["word_ids"]
elmo_embedding = outputs["elmo_embed"]
feed_list = [word_ids.name]
switch_main_program(program)
word_embed_dims = 128
word_embedding = fluid.layers.embedding(
input=word_ids,
size=[word_dict_len, word_embed_dims],
param_attr=fluid.ParamAttr(
learning_rate=30,
initializer=fluid.initializer.Uniform(low=-0.1, high=0.1)))
input_feature = fluid.layers.concat(
input=[elmo_embedding, word_embedding], axis=1)
fc = gru_net(program, input_feature)
elmo_task = hub.TextClassifierTask(
data_reader=reader,
feature=fc,
feed_list=feed_list,
num_classes=dataset.num_labels,
config=config)
elmo_task.finetune_and_eval()
```
**NOTE:**
1. `outputs["elmo_embed"]`返回了ELMo模型预训练的word embedding。
2. `hub.TextClassifierTask`通过输入特征,label与迁移的类别数,可以生成适用于文本分类的迁移任务`TextClassifierTask`
## 可视化
Finetune API训练过程中会自动对关键训练指标进行打点,启动程序后执行下面命令
```bash
$ tensorboard --logdir $CKPT_DIR/visualization --host ${HOST_IP} --port ${PORT_NUM}
```
其中${HOST_IP}为本机IP地址,${PORT_NUM}为可用端口号,如本机IP地址为192.168.0.1,端口号8040,用浏览器打开192.168.0.1:8040,即可看到训练过程中指标的变化情况
## 模型预测
通过Finetune完成模型训练后,在对应的ckpt目录下,会自动保存验证集上效果最好的模型。
配置脚本参数
```
CKPT_DIR="./ckpt_chnsentiment"
python predict.py --checkpoint_dir --use_gpu True
```
其中CKPT_DIR为Finetune API保存最佳模型的路径
参数配置正确后,请执行脚本`sh run_predict.sh`,即可看到以下文本分类预测结果, 以及最终准确率。
如需了解更多预测步骤,请参考`predict.py`
#coding:utf-8
import argparse
import ast
import io
import numpy as np
from paddle.fluid.framework import switch_main_program
import paddle.fluid as fluid
import paddlehub as hub
# yapf: disable
parser = argparse.ArgumentParser(__doc__)
parser.add_argument("--num_epoch", type=int, default=3, help="Number of epoches for fine-tuning.")
parser.add_argument("--use_gpu", type=ast.literal_eval, default=True, help="Whether use GPU for finetuning, input should be True or False")
parser.add_argument("--checkpoint_dir", type=str, default=None, help="Directory to model checkpoint")
parser.add_argument("--batch_size", type=int, default=32, help="Total examples' number in batch for training.")
parser.add_argument("--learning_rate", type=float, default=1e-4, help="Learning rate used to train with warmup.")
parser.add_argument("--weight_decay", type=float, default=5, help="Weight decay rate for L2 regularizer.")
parser.add_argument("--warmup_proportion", type=float, default=0.05, help="Warmup proportion params for warmup strategy")
args = parser.parse_args()
# yapf: enable.
def bow_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
bow = fluid.layers.sequence_pool(input=input_feature, pool_type='sum')
bow_tanh = fluid.layers.tanh(bow)
fc_1 = fluid.layers.fc(input=bow_tanh, size=hid_dim, act="tanh")
fc = fluid.layers.fc(input=fc_1, size=hid_dim2, act="tanh")
return fc
def cnn_net(program, input_feature, win_size=3, hid_dim=128, hid_dim2=96):
switch_main_program(program)
conv_3 = fluid.nets.sequence_conv_pool(
input=input_feature,
num_filters=hid_dim,
filter_size=win_size,
act="relu",
pool_type="max")
fc = fluid.layers.fc(input=conv_3, size=hid_dim2)
return fc
def gru_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
fc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 3)
gru_h = fluid.layers.dynamic_gru(input=fc0, size=hid_dim, is_reverse=False)
gru_max = fluid.layers.sequence_pool(input=gru_h, pool_type='max')
gru_max_tanh = fluid.layers.tanh(gru_max)
fc = fluid.layers.fc(input=gru_max_tanh, size=hid_dim2, act='tanh')
return fc
def bilstm_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
fc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 4)
rfc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 4)
lstm_h, c = fluid.layers.dynamic_lstm(
input=fc0, size=hid_dim * 4, is_reverse=False)
rlstm_h, c = fluid.layers.dynamic_lstm(
input=rfc0, size=hid_dim * 4, is_reverse=True)
# extract last step
lstm_last = fluid.layers.sequence_last_step(input=lstm_h)
rlstm_last = fluid.layers.sequence_last_step(input=rlstm_h)
lstm_last_tanh = fluid.layers.tanh(lstm_last)
rlstm_last_tanh = fluid.layers.tanh(rlstm_last)
# concat layer
lstm_concat = fluid.layers.concat(input=[lstm_last, rlstm_last], axis=1)
# full connect layer
fc = fluid.layers.fc(input=lstm_concat, size=hid_dim2, act='tanh')
return fc
def lstm_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
fc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 4)
lstm_h, c = fluid.layers.dynamic_lstm(
input=fc0, size=hid_dim * 4, is_reverse=False)
lstm_max = fluid.layers.sequence_pool(input=lstm_h, pool_type='max')
lstm_max_tanh = fluid.layers.tanh(lstm_max)
fc = fluid.layers.fc(input=lstm_max_tanh, size=hid_dim2, act='tanh')
return fc
if __name__ == '__main__':
# Step1: load Paddlehub elmo pretrained model
module = hub.Module(name="elmo")
inputs, outputs, program = module.context(trainable=True)
# Step2: Download dataset and use LACClassifyReade to read dataset
dataset = hub.dataset.ChnSentiCorp()
reader = hub.reader.LACClassifyReader(
dataset=dataset, vocab_path=module.get_vocab_path())
word_dict_len = len(reader.vocab)
word_ids = inputs["word_ids"]
elmo_embedding = outputs["elmo_embed"]
# Step3: switch program and build network
# Choose the net which you would like: bow, cnn, gru, bilstm, lstm
switch_main_program(program)
# Embedding layer
word_embed_dims = 128
word_embedding = fluid.layers.embedding(
input=word_ids,
size=[word_dict_len, word_embed_dims],
param_attr=fluid.ParamAttr(
learning_rate=30,
initializer=fluid.initializer.Uniform(low=-0.1, high=0.1)))
# Add elmo embedding
input_feature = fluid.layers.concat(
input=[elmo_embedding, word_embedding], axis=1)
# Choose the net which you would like: bow, cnn, gru, bilstm, lstm
# We recommend you to choose the gru_net
fc = gru_net(program, input_feature)
# Setup feed list for data feeder
# Must feed all the tensor of senta's module need
feed_list = [word_ids.name]
# Step4: Select finetune strategy, setup config and finetune
strategy = hub.AdamWeightDecayStrategy(
weight_decay=args.weight_decay,
learning_rate=args.learning_rate,
lr_scheduler="linear_decay",
warmup_proportion=args.warmup_proportion)
# Step5: Setup runing config for PaddleHub Finetune API
config = hub.RunConfig(
use_cuda=args.use_gpu,
use_data_parallel=True,
use_pyreader=False,
num_epoch=args.num_epoch,
batch_size=args.batch_size,
checkpoint_dir=args.checkpoint_dir,
strategy=strategy)
# Step6: Define a classfication finetune task by PaddleHub's API
elmo_task = hub.TextClassifierTask(
data_reader=reader,
feature=fc,
feed_list=feed_list,
num_classes=dataset.num_labels,
config=config)
# Finetune and evaluate by PaddleHub's API
# will finish training, evaluation, testing, save model automatically
elmo_task.finetune_and_eval()
#coding:utf-8
import argparse
import ast
import io
import numpy as np
from paddle.fluid.framework import switch_main_program
import paddle.fluid as fluid
import paddlehub as hub
# yapf: disable
parser = argparse.ArgumentParser(__doc__)
parser.add_argument("--use_gpu", type=ast.literal_eval, default=True, help="Whether use GPU for finetuning, input should be True or False")
parser.add_argument("--checkpoint_dir", type=str, default=None, help="Directory to model checkpoint")
parser.add_argument("--batch_size", type=int, default=1, help="Total examples' number in batch for training.")
parser.add_argument("--learning_rate", type=float, default=1e-4, help="Learning rate used to train with warmup.")
parser.add_argument("--weight_decay", type=float, default=5, help="Weight decay rate for L2 regularizer.")
parser.add_argument("--warmup_proportion", type=float, default=0.05, help="Warmup proportion params for warmup strategy")
args = parser.parse_args()
# yapf: enable.
def bow_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
bow = fluid.layers.sequence_pool(input=input_feature, pool_type='sum')
bow_tanh = fluid.layers.tanh(bow)
fc_1 = fluid.layers.fc(input=bow_tanh, size=hid_dim, act="tanh")
fc = fluid.layers.fc(input=fc_1, size=hid_dim2, act="tanh")
return fc
def cnn_net(program, input_feature, win_size=3, hid_dim=128, hid_dim2=96):
switch_main_program(program)
conv_3 = fluid.nets.sequence_conv_pool(
input=input_feature,
num_filters=hid_dim,
filter_size=win_size,
act="relu",
pool_type="max")
fc = fluid.layers.fc(input=conv_3, size=hid_dim2)
return fc
def gru_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
fc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 3)
gru_h = fluid.layers.dynamic_gru(input=fc0, size=hid_dim, is_reverse=False)
gru_max = fluid.layers.sequence_pool(input=gru_h, pool_type='max')
gru_max_tanh = fluid.layers.tanh(gru_max)
fc = fluid.layers.fc(input=gru_max_tanh, size=hid_dim2, act='tanh')
return fc
def bilstm_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
fc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 4)
rfc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 4)
lstm_h, c = fluid.layers.dynamic_lstm(
input=fc0, size=hid_dim * 4, is_reverse=False)
rlstm_h, c = fluid.layers.dynamic_lstm(
input=rfc0, size=hid_dim * 4, is_reverse=True)
# extract last step
lstm_last = fluid.layers.sequence_last_step(input=lstm_h)
rlstm_last = fluid.layers.sequence_last_step(input=rlstm_h)
lstm_last_tanh = fluid.layers.tanh(lstm_last)
rlstm_last_tanh = fluid.layers.tanh(rlstm_last)
# concat layer
lstm_concat = fluid.layers.concat(input=[lstm_last, rlstm_last], axis=1)
# full connect layer
fc = fluid.layers.fc(input=lstm_concat, size=hid_dim2, act='tanh')
return fc
def lstm_net(program, input_feature, hid_dim=128, hid_dim2=96):
switch_main_program(program)
fc0 = fluid.layers.fc(input=input_feature, size=hid_dim * 4)
lstm_h, c = fluid.layers.dynamic_lstm(
input=fc0, size=hid_dim * 4, is_reverse=False)
lstm_max = fluid.layers.sequence_pool(input=lstm_h, pool_type='max')
lstm_max_tanh = fluid.layers.tanh(lstm_max)
fc = fluid.layers.fc(input=lstm_max_tanh, size=hid_dim2, act='tanh')
return fc
if __name__ == '__main__':
# Step1: load Paddlehub elmo pretrained model
module = hub.Module(name="elmo")
inputs, outputs, program = module.context(trainable=True)
# Step2: Download dataset and use LACClassifyReade to read dataset
dataset = hub.dataset.ChnSentiCorp()
reader = hub.reader.LACClassifyReader(
dataset=dataset, vocab_path=module.get_vocab_path())
word_dict_len = len(reader.vocab)
word_ids = inputs["word_ids"]
elmo_embedding = outputs["elmo_embed"]
# Step3: switch program and build network
# Choose the net which you would like: bow, cnn, gru, bilstm, lstm
switch_main_program(program)
# Embedding layer
word_embed_dims = 128
word_embedding = fluid.layers.embedding(
input=word_ids,
size=[word_dict_len, word_embed_dims],
param_attr=fluid.ParamAttr(
learning_rate=30,
initializer=fluid.initializer.Uniform(low=-0.1, high=0.1)))
# Add elmo embedding
input_feature = fluid.layers.concat(
input=[elmo_embedding, word_embedding], axis=1)
# Choose the net which you would like: bow, cnn, gru, bilstm, lstm
# We recommend you to choose the gru_net
fc = gru_net(program, input_feature)
# Setup feed list for data feeder
# Must feed all the tensor of senta's module need
feed_list = [word_ids.name]
# Step4: Select finetune strategy, setup config and finetune
strategy = hub.AdamWeightDecayStrategy(
weight_decay=args.weight_decay,
learning_rate=args.learning_rate,
lr_scheduler="linear_decay",
warmup_proportion=args.warmup_proportion)
# Step5: Setup runing config for PaddleHub Finetune API
config = hub.RunConfig(
use_cuda=args.use_gpu,
use_data_parallel=True,
use_pyreader=False,
batch_size=args.batch_size,
checkpoint_dir=args.checkpoint_dir,
strategy=strategy)
# Step6: Define a classfication finetune task by PaddleHub's API
elmo_task = hub.TextClassifierTask(
data_reader=reader,
feature=fc,
feed_list=feed_list,
num_classes=dataset.num_labels,
config=config)
# Data to be prdicted
data = [
"这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般", "交通方便;环境很好;服务态度很好 房间较小",
"还稍微重了点,可能是硬盘大的原故,还要再轻半斤就好了。其他要进一步验证。贴的几种膜气泡较多,用不了多久就要更换了,屏幕膜稍好点,但比没有要强多了。建议配赠几张膜让用用户自己贴。",
"前台接待太差,酒店有A B楼之分,本人check-in后,前台未告诉B楼在何处,并且B楼无明显指示;房间太小,根本不像4星级设施,下次不会再选择入住此店啦",
"19天硬盘就罢工了~~~算上运来的一周都没用上15天~~~可就是不能换了~~~唉~~~~你说这算什么事呀~~~"
]
index = 0
run_states = elmo_task.predict(data=data)
results = [run_state.run_results for run_state in run_states]
for batch_result in results:
# get predict index
batch_result = np.argmax(batch_result, axis=2)[0]
for result in batch_result:
print("%s\tpredict=%s" % (data[index], result))
index += 1
# PaddleHub 图像分类
## 关于
本示例将展示如何使用PaddleHub Finetune API以及[图像分类](https://github.com/PaddlePaddle/models/tree/release/v1.2/PaddleCV/image_classification)预训练模型完成分类任务。
## 准备工作
在运行本目录的脚本前,需要先安装1.3.0版本以上的PaddlePaddle(如果您本地已经安装了符合条件的PaddlePaddle版本,那么可以跳过`准备工作`这一步)。
如果您的机器支持GPU,我们建议下载GPU版本的PaddlePaddle,使用GPU进行训练和预测的效率都比使用CPU要高。
```shell
# 安装GPU版本的PaddlePaddle
$ pip install --upgrade paddlepaddle-gpu
```
如果您的机器不支持GPU,可以通过下面的命令来安装CPU版本的PaddlePaddle
```shell
# 安装CPU版本的PaddlePaddle
$ pip install --upgrade paddlepaddle
```
在安装过程中如果遇到问题,您可以到[Paddle官方网站](http://www.paddlepaddle.org/)上查看解决方案。
## 开始Fine-tune
在完成安装PaddlePaddle与PaddleHub后,通过执行脚本`sh run_classifier.sh`即可开始使用进行finetune。
脚本支持的参数如下:
```shell
--batch_size: 批处理大小,请结合显存情况进行调整,若出现显存不足,请适当调低这一参数。默认为16
--num_epoch: finetune迭代的轮数。默认为1
--module: 使用哪个Module作为finetune的特征提取器,脚本支持{resnet50/resnet101/resnet152/mobilenet/nasnet/pnasnet}等模型。默认为resnet50
--checkpoint_dir: 模型保存路径,PaddleHub会自动保存验证集上表现最好的模型。默认为paddlehub_finetune_ckpt
--dataset: 使用什么数据集进行finetune, 脚本支持分别是{flowers/dogcat/stanforddogs/indoor67/food101}。默认为flowers
--use_gpu: 是否使用GPU进行训练,如果机器支持GPU且安装了GPU版本的PaddlePaddle,我们建议您打开这个开关。默认关闭
--use_data_parallel: 是否使用数据并行,打开该开关时,会将数据分散到不同的卡上进行训练(CPU下会分布到不同线程)。默认关闭
--use_pyreader: 是否使用pyreader进行数据喂入。默认关闭
```
## 进行预测
当完成finetune后,finetune过程在验证集上表现最优的模型会被保存在`${CHECKPOINT_DIR}/best_model`目录下,其中`${CHECKPOINT_DIR}`目录为finetune时所选择的保存checkpoint的目录。
我们使用该模型来进行预测。执行脚本`sh predict.sh`即可开始使用进行预测。
脚本支持的参数如下:
```shell
--module: 使用哪个Module作为finetune的特征提取器,脚本支持{resnet50/resnet101/resnet152/mobilenet/nasnet/pnasnet}等模型。默认为resnet50
--checkpoint_dir: 模型保存路径,PaddleHub会自动保存验证集上表现最好的模型。默认为paddlehub_finetune_ckpt
--dataset: 使用什么数据集进行finetune, 脚本支持分别是{flowers/dogcat}。默认为flowers
--use_gpu: 使用使用GPU进行训练,如果本机支持GPU且安装了GPU版本的PaddlePaddle,我们建议您打开这个开关。默认关闭
--use_pyreader: 是否使用pyreader进行数据喂入。默认关闭
```
`注意`:进行预测时,所选择的module,checkpoint_dir,dataset必须和finetune所用的一样
# PaddleHub 图像分类
本示例将展示如何使用PaddleHub Fine-tune API以及[ResNet](https://www.paddlepaddle.org.cn/hubdetail?name=resnet_v2_50_imagenet&en_category=ImageClassification)等预训练模型完成分类任务。
## 如何开始Fine-tune
在完成安装PaddlePaddle与PaddleHub后,通过执行脚本`sh run_classifier.sh`即可开始使用ResNet对[Flowers](../../docs/reference/dataset.md#class-hubdatasetflowers)等数据集进行Fine-tune。
其中脚本参数说明如下:
```shell
--batch_size: 批处理大小,请结合显存情况进行调整,若出现显存不足,请适当调低这一参数。默认为16;
--num_epoch: Fine-tune迭代的轮数。默认为1;
--module: 使用哪个Module作为Fine-tune的特征提取器,脚本支持{resnet50/resnet101/resnet152/mobilenet/nasnet/pnasnet}等模型。默认为resnet50;
--checkpoint_dir: 模型保存路径,PaddleHub会自动保存验证集上表现最好的模型。默认为paddlehub_finetune_ckpt;
--dataset: 使用什么数据集进行Fine-tune, 脚本支持分别是{flowers/dogcat/stanforddogs/indoor67/food101}。默认为flowers;
--use_gpu: 是否使用GPU进行训练,如果机器支持GPU且安装了GPU版本的PaddlePaddle,我们建议您打开这个开关。默认关闭;
--use_data_parallel: 是否使用数据并行,打开该开关时,会将数据分散到不同的卡上进行训练(CPU下会分布到不同线程)。默认打开;
```
## 代码步骤
使用PaddleHub Fine-tune API进行Fine-tune可以分为4个步骤。
### Step1: 加载预训练模型
```python
module = hub.Module(name="resnet_v2_50_imagenet")
inputs, outputs, program = module.context(trainable=True)
```
PaddleHub提供许多图像分类预训练模型,如xception、mobilenet、efficientnet等,详细信息参见[图像分类模型](https://www.paddlepaddle.org.cn/hub?filter=en_category&value=ImageClassification)
如果想尝试efficientnet模型,只需要更换Module中的`name`参数即可.
```python
# 更换name参数即可无缝切换efficientnet模型, 代码示例如下
module = hub.Module(name="efficientnetb7_imagenet")
```
### Step2: 下载数据集并使用ImageClassificationReader读取数据
```python
dataset = hub.dataset.Flowers()
data_reader = hub.reader.ImageClassificationReader(
image_width=module.get_expected_image_width(),
image_height=module.get_expected_image_height(),
images_mean=module.get_pretrained_images_mean(),
images_std=module.get_pretrained_images_std(),
dataset=dataset)
```
其中数据集的准备代码可以参考 [flowers.py](../../paddlehub/dataset/flowers.py)
同时,PaddleHub提供了更多的图像分类数据集:
| 数据集 | API |
| -------- | ------------------------------------------ |
| Flowers | hub.dataset.Flowers() |
| DogCat | hub.dataset.DogCat() |
| Indoor67 | hub.dataset.Indoor67() |
| Food101 | hub.dataset.Food101() |
`hub.dataset.Flowers()` 会自动从网络下载数据集并解压到用户目录下`$HOME/.paddlehub/dataset`目录。
`module.get_expected_image_width()``module.get_expected_image_height()`会返回预训练模型对应的图片尺寸。
`module.module.get_pretrained_images_mean()``module.get_pretrained_images_std()`会返回预训练模型对应的图片均值和方差。
#### 自定义数据集
如果想加载自定义数据集完成迁移学习,详细参见[自定义数据集](../../docs/tutorial/how_to_load_data.md)
### Step3:选择优化策略和运行配置
```python
strategy = hub.DefaultFinetuneStrategy(
learning_rate=1e-4,
optimizer_name="adam",
regularization_coeff=1e-3)
config = hub.RunConfig(use_cuda=True, use_data_parallel=True, num_epoch=3, batch_size=32, strategy=strategy)
```
#### 优化策略
PaddleHub提供了许多优化策略,如`AdamWeightDecayStrategy``ULMFiTStrategy``DefaultFinetuneStrategy`等,详细信息参见[策略](../../docs/reference/strategy.md)
其中`DefaultFinetuneStrategy`:
* `learning_rate`: 全局学习率。默认为1e-4;
* `optimizer_name`: 优化器名称。默认adam;
* `regularization_coeff`: 正则化的λ参数。默认为1e-3;
#### 运行配置
`RunConfig` 主要控制Fine-tune的训练,包含以下可控制的参数:
* `log_interval`: 进度日志打印间隔,默认每10个step打印一次;
* `eval_interval`: 模型评估的间隔,默认每100个step评估一次验证集;
* `save_ckpt_interval`: 模型保存间隔,请根据任务大小配置,默认只保存验证集效果最好的模型和训练结束的模型;
* `use_cuda`: 是否使用GPU训练,默认为False;
* `use_pyreader`: 是否使用pyreader,默认False;
* `use_data_parallel`: 是否使用并行计算,默认True。打开该功能依赖nccl库;
* `checkpoint_dir`: 模型checkpoint保存路径, 若用户没有指定,程序会自动生成;
* `num_epoch`: Fine-tune的轮数;
* `batch_size`: 训练的批大小,如果使用GPU,请根据实际情况调整batch_size;
* `strategy`: Fine-tune优化策略;
### Step4: 构建网络并创建分类迁移任务进行Fine-tune
```python
feature_map = output_dict["feature_map"]
feed_list = [input_dict["image"].name]
task = hub.ImageClassifierTask(
data_reader=data_reader,
feed_list=feed_list,
feature=feature_map,
num_classes=dataset.num_labels,
config=config)
task.finetune_and_eval()
```
**NOTE:**
1. `output_dict["feature_map"]`返回了resnet/mobilenet等模型对应的feature_map,可以用于图片的特征表达。
2. `feed_list`中的inputs参数指明了resnet/mobilenet等模型的输入tensor的顺序,与ImageClassifierTask返回的结果一致。
3. `hub.ImageClassifierTask`通过输入特征,label与迁移的类别数,可以生成适用于图像分类的迁移任务`ImageClassifierTask`
#### 自定义迁移任务
如果想改变迁移任务组网,详细参见[自定义迁移任务](../../docs/tutorial/how_to_define_task.md)
## 可视化
Fine-tune API训练过程中会自动对关键训练指标进行打点,启动程序后执行下面命令
```bash
$ visualdl --logdir $CKPT_DIR/visualization --host ${HOST_IP} --port ${PORT_NUM}
```
其中${HOST_IP}为本机IP地址,${PORT_NUM}为可用端口号,如本机IP地址为192.168.0.1,端口号8040,用浏览器打开192.168.0.1:8040,即可看到训练过程中指标的变化情况。
## 模型预测
当完成Fine-tune后,Fine-tune过程在验证集上表现最优的模型会被保存在`${CHECKPOINT_DIR}/best_model`目录下,其中`${CHECKPOINT_DIR}`目录为Fine-tune时所选择的保存checkpoint的目录。
我们使用该模型来进行预测。predict.py脚本支持的参数如下:
```shell
--module: 使用哪个Module作为Fine-tune的特征提取器,脚本支持{resnet50/resnet101/resnet152/mobilenet/nasnet/pnasnet}等模型。默认为resnet50;
--checkpoint_dir: 模型保存路径,PaddleHub会自动保存验证集上表现最好的模型。默认为paddlehub_finetune_ckpt;
--dataset: 使用什么数据集进行Fine-tune, 脚本支持分别是{flowers/dogcat}。默认为flowers;
--use_gpu: 使用使用GPU进行训练,如果本机支持GPU且安装了GPU版本的PaddlePaddle,我们建议您打开这个开关。默认关闭;
--use_pyreader: 是否使用pyreader进行数据喂入。默认关闭;
```
**NOTE:** 进行预测时,所选择的module,checkpoint_dir,dataset必须和Fine-tune所用的一样。
参数配置正确后,请执行脚本`sh run_predict.sh`,即可看到以下图片分类预测结果。
如需了解更多预测步骤,请参考`predict.py`
我们在AI Studio上提供了IPython NoteBook形式的demo,您可以直接在平台上在线体验,链接如下:
|预训练模型|任务类型|数据集|AIStudio链接|备注|
|-|-|-|-|-|
|ResNet|图像分类|猫狗数据集DogCat|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/147010)||
|ERNIE|文本分类|中文情感分类数据集ChnSentiCorp|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/147006)||
|ERNIE|文本分类|中文新闻分类数据集THUNEWS|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/221999)|本教程讲述了如何将自定义数据集加载,并利用Fine-tune API完成文本分类迁移学习。|
|ERNIE|序列标注|中文序列标注数据集MSRA_NER|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/147009)||
|ERNIE|序列标注|中文快递单数据集Express|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/184200)|本教程讲述了如何将自定义数据集加载,并利用Fine-tune API完成序列标注迁移学习。|
|ERNIE Tiny|文本分类|中文情感分类数据集ChnSentiCorp|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/186443)||
|Senta|文本分类|中文情感分类数据集ChnSentiCorp|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/216846)|本教程讲述了任何利用Senta和Fine-tune API完成情感分类迁移学习。|
|Senta|情感分析预测|N/A|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/215814)||
|LAC|词法分析|N/A|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/215711)||
|Ultra-Light-Fast-Generic-Face-Detector-1MB|人脸检测|N/A|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/215962)||
## 超参优化AutoDL Finetuner
PaddleHub还提供了超参优化(Hyperparameter Tuning)功能, 自动搜索最优模型超参得到更好的模型效果。详细信息参见[AutoDL Finetuner超参优化功能教程](../../docs/tutorial/autofinetune.md)
...@@ -14,8 +14,7 @@ parser.add_argument("--use_gpu", type=ast.literal_eval, default=True ...@@ -14,8 +14,7 @@ parser.add_argument("--use_gpu", type=ast.literal_eval, default=True
parser.add_argument("--checkpoint_dir", type=str, default="paddlehub_finetune_ckpt", help="Path to save log data.") parser.add_argument("--checkpoint_dir", type=str, default="paddlehub_finetune_ckpt", help="Path to save log data.")
parser.add_argument("--batch_size", type=int, default=16, help="Total examples' number in batch for training.") parser.add_argument("--batch_size", type=int, default=16, help="Total examples' number in batch for training.")
parser.add_argument("--module", type=str, default="resnet50", help="Module used as feature extractor.") parser.add_argument("--module", type=str, default="resnet50", help="Module used as feature extractor.")
parser.add_argument("--dataset", type=str, default="flowers", help="Dataset to finetune.") parser.add_argument("--dataset", type=str, default="flowers", help="Dataset to fine-tune.")
parser.add_argument("--use_pyreader", type=ast.literal_eval, default=True, help="Whether use pyreader to feed data.")
parser.add_argument("--use_data_parallel", type=ast.literal_eval, default=True, help="Whether use data parallel.") parser.add_argument("--use_data_parallel", type=ast.literal_eval, default=True, help="Whether use data parallel.")
# yapf: enable. # yapf: enable.
...@@ -30,9 +29,11 @@ module_map = { ...@@ -30,9 +29,11 @@ module_map = {
def finetune(args): def finetune(args):
# Load Paddlehub pretrained model
module = hub.Module(name=args.module) module = hub.Module(name=args.module)
input_dict, output_dict, program = module.context(trainable=True) input_dict, output_dict, program = module.context(trainable=True)
# Download dataset
if args.dataset.lower() == "flowers": if args.dataset.lower() == "flowers":
dataset = hub.dataset.Flowers() dataset = hub.dataset.Flowers()
elif args.dataset.lower() == "dogcat": elif args.dataset.lower() == "dogcat":
...@@ -46,6 +47,7 @@ def finetune(args): ...@@ -46,6 +47,7 @@ def finetune(args):
else: else:
raise ValueError("%s dataset is not defined" % args.dataset) raise ValueError("%s dataset is not defined" % args.dataset)
# Use ImageClassificationReader to read dataset
data_reader = hub.reader.ImageClassificationReader( data_reader = hub.reader.ImageClassificationReader(
image_width=module.get_expected_image_width(), image_width=module.get_expected_image_width(),
image_height=module.get_expected_image_height(), image_height=module.get_expected_image_height(),
...@@ -55,25 +57,27 @@ def finetune(args): ...@@ -55,25 +57,27 @@ def finetune(args):
feature_map = output_dict["feature_map"] feature_map = output_dict["feature_map"]
img = input_dict["image"] # Setup feed list for data feeder
feed_list = [img.name] feed_list = [input_dict["image"].name]
# Setup RunConfig for PaddleHub Fine-tune API
config = hub.RunConfig( config = hub.RunConfig(
use_data_parallel=args.use_data_parallel, use_data_parallel=args.use_data_parallel,
use_pyreader=args.use_pyreader,
use_cuda=args.use_gpu, use_cuda=args.use_gpu,
num_epoch=args.num_epoch, num_epoch=args.num_epoch,
batch_size=args.batch_size, batch_size=args.batch_size,
enable_memory_optim=False,
checkpoint_dir=args.checkpoint_dir, checkpoint_dir=args.checkpoint_dir,
strategy=hub.finetune.strategy.DefaultFinetuneStrategy()) strategy=hub.finetune.strategy.DefaultFinetuneStrategy())
# Define a image classification task by PaddleHub Fine-tune API
task = hub.ImageClassifierTask( task = hub.ImageClassifierTask(
data_reader=data_reader, data_reader=data_reader,
feed_list=feed_list, feed_list=feed_list,
feature=feature_map, feature=feature_map,
num_classes=dataset.num_labels, num_classes=dataset.num_labels,
config=config) config=config)
# Fine-tune by PaddleHub's API
task.finetune_and_eval() task.finetune_and_eval()
......
#coding:utf-8
import argparse
import os
import numpy as np
import paddlehub as hub
import paddle.fluid as fluid
from paddle.fluid.dygraph import Linear
from paddle.fluid.dygraph.base import to_variable
from paddle.fluid.optimizer import AdamOptimizer
# yapf: disable
parser = argparse.ArgumentParser(__doc__)
parser.add_argument("--num_epoch", type=int, default=1, help="Number of epoches for fine-tuning.")
parser.add_argument("--checkpoint_dir", type=str, default="paddlehub_finetune_ckpt_dygraph", help="Path to save log data.")
parser.add_argument("--batch_size", type=int, default=16, help="Total examples' number in batch for training.")
parser.add_argument("--log_interval", type=int, default=10, help="log interval.")
parser.add_argument("--save_interval", type=int, default=10, help="save interval.")
# yapf: enable.
class ResNet50(fluid.dygraph.Layer):
def __init__(self, num_classes, backbone):
super(ResNet50, self).__init__()
self.fc = Linear(input_dim=2048, output_dim=num_classes)
self.backbone = backbone
def forward(self, imgs):
feature_map = self.backbone(imgs)
feature_map = fluid.layers.reshape(feature_map, shape=[-1, 2048])
pred = self.fc(feature_map)
return fluid.layers.softmax(pred)
def finetune(args):
with fluid.dygraph.guard():
resnet50_vd_10w = hub.Module(name="resnet50_vd_10w")
dataset = hub.dataset.Flowers()
resnet = ResNet50(
num_classes=dataset.num_labels, backbone=resnet50_vd_10w)
adam = AdamOptimizer(
learning_rate=0.001, parameter_list=resnet.parameters())
state_dict_path = os.path.join(args.checkpoint_dir,
'dygraph_state_dict')
if os.path.exists(state_dict_path + '.pdparams'):
state_dict, _ = fluid.load_dygraph(state_dict_path)
resnet.load_dict(state_dict)
reader = hub.reader.ImageClassificationReader(
image_width=resnet50_vd_10w.get_expected_image_width(),
image_height=resnet50_vd_10w.get_expected_image_height(),
images_mean=resnet50_vd_10w.get_pretrained_images_mean(),
images_std=resnet50_vd_10w.get_pretrained_images_std(),
dataset=dataset)
train_reader = reader.data_generator(
batch_size=args.batch_size, phase='train')
loss_sum = acc_sum = cnt = 0
# 执行epoch_num次训练
for epoch in range(args.num_epoch):
# 读取训练数据进行训练
for batch_id, data in enumerate(train_reader()):
imgs = np.array(data[0][0])
labels = np.array(data[0][1])
pred = resnet(imgs)
acc = fluid.layers.accuracy(pred, to_variable(labels))
loss = fluid.layers.cross_entropy(pred, to_variable(labels))
avg_loss = fluid.layers.mean(loss)
avg_loss.backward()
# 参数更新
adam.minimize(avg_loss)
loss_sum += avg_loss.numpy() * imgs.shape[0]
acc_sum += acc.numpy() * imgs.shape[0]
cnt += imgs.shape[0]
if batch_id % args.log_interval == 0:
print('epoch {}: loss {}, acc {}'.format(
epoch, loss_sum / cnt, acc_sum / cnt))
loss_sum = acc_sum = cnt = 0
if batch_id % args.save_interval == 0:
state_dict = resnet.state_dict()
fluid.save_dygraph(state_dict, state_dict_path)
if __name__ == "__main__":
args = parser.parse_args()
finetune(args)
...@@ -9,12 +9,11 @@ import numpy as np ...@@ -9,12 +9,11 @@ import numpy as np
# yapf: disable # yapf: disable
parser = argparse.ArgumentParser(__doc__) parser = argparse.ArgumentParser(__doc__)
parser.add_argument("--use_gpu", type=ast.literal_eval, default=False, help="Whether use GPU for predict.") parser.add_argument("--use_gpu", type=ast.literal_eval, default=True, help="Whether use GPU for predict.")
parser.add_argument("--checkpoint_dir", type=str, default="paddlehub_finetune_ckpt", help="Path to save log data.") parser.add_argument("--checkpoint_dir", type=str, default="paddlehub_finetune_ckpt", help="Path to save log data.")
parser.add_argument("--batch_size", type=int, default=16, help="Total examples' number in batch for training.") parser.add_argument("--batch_size", type=int, default=16, help="Total examples' number in batch for training.")
parser.add_argument("--module", type=str, default="resnet50", help="Module used as a feature extractor.") parser.add_argument("--module", type=str, default="resnet50", help="Module used as a feature extractor.")
parser.add_argument("--dataset", type=str, default="flowers", help="Dataset to finetune.") parser.add_argument("--dataset", type=str, default="flowers", help="Dataset to fine-tune.")
parser.add_argument("--use_pyreader", type=ast.literal_eval, default=False, help="Whether use pyreader to feed data.")
# yapf: enable. # yapf: enable.
module_map = { module_map = {
...@@ -28,9 +27,11 @@ module_map = { ...@@ -28,9 +27,11 @@ module_map = {
def predict(args): def predict(args):
# Load Paddlehub pretrained model
module = hub.Module(name=args.module) module = hub.Module(name=args.module)
input_dict, output_dict, program = module.context(trainable=True) input_dict, output_dict, program = module.context(trainable=True)
# Download dataset
if args.dataset.lower() == "flowers": if args.dataset.lower() == "flowers":
dataset = hub.dataset.Flowers() dataset = hub.dataset.Flowers()
elif args.dataset.lower() == "dogcat": elif args.dataset.lower() == "dogcat":
...@@ -44,6 +45,7 @@ def predict(args): ...@@ -44,6 +45,7 @@ def predict(args):
else: else:
raise ValueError("%s dataset is not defined" % args.dataset) raise ValueError("%s dataset is not defined" % args.dataset)
# Use ImageClassificationReader to read dataset
data_reader = hub.reader.ImageClassificationReader( data_reader = hub.reader.ImageClassificationReader(
image_width=module.get_expected_image_width(), image_width=module.get_expected_image_width(),
image_height=module.get_expected_image_height(), image_height=module.get_expected_image_height(),
...@@ -53,19 +55,19 @@ def predict(args): ...@@ -53,19 +55,19 @@ def predict(args):
feature_map = output_dict["feature_map"] feature_map = output_dict["feature_map"]
img = input_dict["image"] # Setup feed list for data feeder
feed_list = [img.name] feed_list = [input_dict["image"].name]
# Setup RunConfig for PaddleHub Fine-tune API
config = hub.RunConfig( config = hub.RunConfig(
use_data_parallel=False, use_data_parallel=False,
use_pyreader=args.use_pyreader,
use_cuda=args.use_gpu, use_cuda=args.use_gpu,
batch_size=args.batch_size, batch_size=args.batch_size,
enable_memory_optim=False,
checkpoint_dir=args.checkpoint_dir, checkpoint_dir=args.checkpoint_dir,
strategy=hub.finetune.strategy.DefaultFinetuneStrategy()) strategy=hub.finetune.strategy.DefaultFinetuneStrategy())
task = hub.ClassifierTask( # Define a image classification task by PaddleHub Fine-tune API
task = hub.ImageClassifierTask(
data_reader=data_reader, data_reader=data_reader,
feed_list=feed_list, feed_list=feed_list,
feature=feature_map, feature=feature_map,
...@@ -73,19 +75,7 @@ def predict(args): ...@@ -73,19 +75,7 @@ def predict(args):
config=config) config=config)
data = ["./test/test_img_daisy.jpg", "./test/test_img_roses.jpg"] data = ["./test/test_img_daisy.jpg", "./test/test_img_roses.jpg"]
label_map = dataset.label_dict() print(task.predict(data=data, return_result=True))
index = 0
# get classification result
run_states = task.predict(data=data)
results = [run_state.run_results for run_state in run_states]
for batch_result in results:
# get predict index
batch_result = np.argmax(batch_result, axis=2)[0]
for result in batch_result:
index += 1
result = label_map[result]
print("input %i is %s, and the predict result is %s" %
(index, data[index - 1], result))
if __name__ == "__main__": if __name__ == "__main__":
......
# LAC # LAC 词法分析
## 关于
本示例展示如何使用LAC Module进行预测。 本示例展示如何使用LAC Module进行预测。
LAC是中文词法分析模型,可以用于进行中文句子的分词/词性标注/命名实体识别等功能,关于模型的训练细节,请查看[LAC](https://github.com/baidu/lac) LAC是中文词法分析模型,可以用于进行中文句子的分词/词性标注/命名实体识别等功能,关于模型的细节参见[模型介绍](https://www.paddlepaddle.org.cn/hubdetail?name=lac&en_category=LexicalAnalysis)
## 准备工作
在运行本目录的脚本前,需要先安装1.3.0版本以上的PaddlePaddle(如果您本地已经安装了符合条件的PaddlePaddle版本,那么可以跳过`准备工作`这一步)。 ## 命令行方式预测
`cli_demo.sh`给出了使用命令行接口(Command Line Interface)调用Module预测的示例脚本,
通过以下命令试验下效果。
如果您的机器支持GPU,我们建议下载GPU版本的PaddlePaddle,使用GPU进行训练和预测的效率都比使用CPU要高。
```shell ```shell
# 安装GPU版本的PaddlePaddle $ hub run lac --input_text "今天是个好日子"
$ pip install --upgrade paddlepaddle-gpu $ hub run lac --input_file test.txt --user_dict user.dict
``` ```
test.txt 存放待分词文本, 如:
如果您的机器不支持GPU,可以通过下面的命令来安装CPU版本的PaddlePaddle ```text
今天是个好日子
```shell 今天天气晴朗
# 安装CPU版本的PaddlePaddle
$ pip install --upgrade paddlepaddle
``` ```
user.dict为用户自定义词典,可以不指定,当指定自定义词典时,可以干预默认分词结果。
词典包含三列,第一列为单词,第二列为单词词性,第三列为单词词频,以水平制表符\t分隔。词频越高的单词,对分词结果影响越大,词典样例如下:
在安装过程中如果遇到问题,您可以到[Paddle官方网站](http://www.paddlepaddle.org/)上查看解决方案。 ```text
天气预报 n 400000
经 v 1000
常 d 1000
```
## 命令行方式预测 **NOTE:**
`cli_demo.sh`给出了使用命令行接口(Command Line Interface)调用Module预测的示例脚本 * 该PaddleHub Module使用词典干预功能时,依赖于第三方库pyahocorasick,请自行安装;
通过以下命令试验下效果 * 请不要直接复制示例文本使用,复制后的格式可能存在问题;
```shell
$ sh cli_demo.sh
```
## 通过Python API预测 ## 通过Python API预测
`lac_demo.py`给出了使用python API调用PaddleHub LAC Module预测的示例代码 `lac_demo.py`给出了使用python API调用PaddleHub LAC Module预测的示例代码
通过以下命令试验下效果 通过以下命令试验下效果
```shell ```shell
python lac_demo.py python lac_demo.py
......
python ../../paddlehub/commands/hub.py run lac --input_file test/test.txt
今天是个好日子
天气预报说今天要下雨
下一班地铁马上就要到了
input_data:
text:
type : TEXT
key : TEXT_INPUT
# 基于PaddleHub实现口罩佩戴检测应用
本文档基于飞桨本次开源的口罩佩戴识别模型, 提供了一个完整的支持视频流的Web Demo,以及高性能的Python和C++集成部署方案, 适用于不同场景下的软件集成。
## 目录
- [1. 搭建视频流场景的WebDemo](#1-搭建视频流场景webdemo)
- [2. 高性能Python部署方案](#2-高性能Python部署方案)
- [3. 高性能C++部署方案](#3-高性能c部署方案)
## 1. 搭建视频流场景WebDemo
![image](./images/web1.jpg)
### [>点击查看视频链接<](https://www.bilibili.com/video/av88962128)
### 背景
本项目可以部署在大型场馆出入口,学校,医院,交通通道出入口,人脸识别闸机,机器人上,支持的方案有:安卓方案(如RK3399的人脸识别机,机器人),Ubuntu 边缘计算,WindowsPC+摄像头,识别率80%~90%,如果立项使用场景可以达到 99% (如:人脸识别机场景)。但是限于清晰度和遮挡关系,对应用场景有一些要求。
### 效果分析
可以看到识别率在80~90%之前,稍小的人脸有误识别的情况,有些挡住嘴的场景也被误识别成了戴口罩,一个人带着口罩,鼻子漏出来识别成没有戴口罩,这个是合理的因为的鼻子漏出来是佩戴不规范。这个模型应用在门口,狭长通道,人脸识别机所在位置都是可以的。
![image](./images/mask1.jpg)![image](./images/mask2.jpg)![image](./images/mask3.jpg)
### 1.1 部署环境
参考: https://www.paddlepaddle.org.cn/install/quick
#### 安装paddlehub
`pip install paddlehub`
### 1.2 开发识别服务
#### 加载预训练模型
```python
import paddlehub as hub
module = hub.Module(name="pyramidbox_lite_server_mask") #口罩检测模型
```
>以上语句paddlehub会自动下载口罩检测模型 "pyramidbox_lite_mobile_mask" 不需要提前下载模型
#### OpenCV打开摄像头或视频文件
下载测试视频
```
wget https://paddlehub.bj.bcebos.com/mask_detection/test_video.mp4
```
```python
import cv2
capture = cv2.VideoCapture(0) # 打开摄像头
# capture = cv2.VideoCapture('./test_video.mp4') # 打开视频文件
while(1):
ret, frame = capture.read() # frame即视频的一帧数据
if ret == False:
break
cv2.imshow('Mask Detection', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
```
#### 口罩佩戴检测
```python
# frame为一帧数据
input_dict = {"data": [frame]}
results = module.face_detection(data=input_dict)
print(results)
```
输出结果:
```json
[
{
"data": {
"label": "MASK",
"left": 258.37087631225586,
"right": 374.7980499267578,
"top": 122.76758193969727,
"bottom": 254.20085906982422,
"confidence": 0.5630852
},
"id": 1
}
]
```
>"label":是否戴口罩,"confidence":置信度,其余字段为脸框的位置大小
#### 将结果显示到原视频帧中
```python
# results为口罩检测结果
for result in results:
# print(result)
label = result['data']['label']
confidence = result['data']['confidence']
top, right, bottom, left = int(result['data']['top']), int(result['data']['right']), int(result['data']['bottom']), int(result['data']['left'])
color = (0, 255, 0)
if label == 'NO MASK':
color = (0, 0, 255)
cv2.rectangle(frame, (left, top), (right, bottom), color, 3)
cv2.putText(frame, label + ":" + str(confidence), (left, top-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
```
![image](./images/maskdetection_1.jpg)
>原DEMO中是英文+置信度显示在框的上面,尝试改为中文,遇到字体问题,以下是解决办法
#### 图片写入中文
需要事先准备ttf/otf等格式的字体文件
```python
def paint_chinese_opencv(im,chinese,position,fontsize,color_bgr):
img_PIL = Image.fromarray(cv2.cvtColor(im,cv2.COLOR_BGR2RGB)) # 图像从OpenCV格式转换成PIL格式
font = ImageFont.truetype('思源黑体SC-Heavy.otf',fontsize,encoding="utf-8") # 加载字体文件
#color = (255,0,0) # 字体颜色
#position = (100,100) # 文字输出位置
color = color_bgr[::-1]
draw = ImageDraw.Draw(img_PIL)
# PIL图片上打印汉字 # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体
draw.text(position,chinese,font=font,fill=color)
img = cv2.cvtColor(np.asarray(img_PIL),cv2.COLOR_RGB2BGR)# PIL图片转cv2图片
return img
```
```python
for result in results:
label = result['data']['label']
confidence = result['data']['confidence']
top, right, bottom, left = int(result['data']['top']), int(result['data']['right']), int(result['data']['bottom']), int(result['data']['left'])
color = (0, 255, 0)
label_cn = "有口罩"
if label == 'NO MASK':
color = (0, 0, 255)
label_cn = "无口罩"
cv2.rectangle(frame, (left, top), (right, bottom), color, 3)
# cv2.putText(frame, label + ":" + str(confidence), (left, top-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
frame = paint_chinese_opencv(frame, label_cn + ":" + str(confidence), (left, top-36), 24, color)
```
![image](./images/maskdetection_2.jpg)
#### 提取头像文件
```python
img_name = "avatar_%d.png" % (maskIndex)
path = "./result/" + img_name
image = frame[top - 10: bottom + 10, left - 10: right + 10]
cv2.imwrite(path, image,[int(cv2.IMWRITE_PNG_COMPRESSION), 9])
```
#### 结果写入JSON
```python
with open("./result/2-mask_detection.json","w") as f:
json.dump(data, f)
```
>此处可以按照自己的应用需要改为输出到mysql,Redis,kafka ,MQ 供应用消化数据
完整代码可以参考`mask_detection.py`
### 1.3 制作网页呈现效果
此DEMO是显示一个固定视频,分析导出的 json 渲染到网页里面,如需实时显示需要再次开发
#### python 导出的数据
使用上面的 python 文件完整执行后会有3个种类的数据输出,放到`web/video/result`目录下
![image](./images/result.jpg)
#### json数据结构
![image](./images/json.jpg)
#### 使用数据渲染网页
- 网页中左侧 "视频播放视频区",播放同时实时回调当前播放的时间点
- 根据时间点换算为帧(1秒30帧),遍历 json 数据中的数据
- 把数据中对应的数据输出到网页右侧 "信息区"
![image](./images/web2.jpg)
## 2. 高性能Python部署方案
更多信息可以参考[文档](./python/README.md)
## 3. 高性能C++部署方案
更多信息可以参考[文档](./cpp/README.md)
## 欢迎交流
**百度飞桨合作伙伴:**
![image](./images/logo.jpg)
北京奇想天外科技有限公司
cmake_minimum_required(VERSION 3.0)
project(PaddleMaskDetector CXX C)
option(WITH_MKL "Compile demo with MKL/OpenBlas support,defaultuseMKL." ON)
option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." ON)
option(WITH_STATIC_LIB "Compile demo with static/shared library, default use static." ON)
option(USE_TENSORRT "Compile demo with TensorRT." OFF)
SET(PADDLE_DIR "" CACHE PATH "Location of libraries")
SET(OPENCV_DIR "" CACHE PATH "Location of libraries")
SET(CUDA_LIB "" CACHE PATH "Location of libraries")
macro(safe_set_static_flag)
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif(${flag_var} MATCHES "/MD")
endforeach(flag_var)
endmacro()
if (WITH_MKL)
ADD_DEFINITIONS(-DUSE_MKL)
endif()
if (NOT DEFINED PADDLE_DIR OR ${PADDLE_DIR} STREQUAL "")
message(FATAL_ERROR "please set PADDLE_DIR with -DPADDLE_DIR=/path/paddle_influence_dir")
endif()
if (NOT DEFINED OPENCV_DIR OR ${OPENCV_DIR} STREQUAL "")
message(FATAL_ERROR "please set OPENCV_DIR with -DOPENCV_DIR=/path/opencv")
endif()
include_directories("${CMAKE_SOURCE_DIR}/")
include_directories("${PADDLE_DIR}/")
include_directories("${PADDLE_DIR}/third_party/install/protobuf/include")
include_directories("${PADDLE_DIR}/third_party/install/glog/include")
include_directories("${PADDLE_DIR}/third_party/install/gflags/include")
include_directories("${PADDLE_DIR}/third_party/install/xxhash/include")
if (EXISTS "${PADDLE_DIR}/third_party/install/snappy/include")
include_directories("${PADDLE_DIR}/third_party/install/snappy/include")
endif()
if(EXISTS "${PADDLE_DIR}/third_party/install/snappystream/include")
include_directories("${PADDLE_DIR}/third_party/install/snappystream/include")
endif()
include_directories("${PADDLE_DIR}/third_party/install/zlib/include")
include_directories("${PADDLE_DIR}/third_party/boost")
include_directories("${PADDLE_DIR}/third_party/eigen3")
if (EXISTS "${PADDLE_DIR}/third_party/install/snappy/lib")
link_directories("${PADDLE_DIR}/third_party/install/snappy/lib")
endif()
if(EXISTS "${PADDLE_DIR}/third_party/install/snappystream/lib")
link_directories("${PADDLE_DIR}/third_party/install/snappystream/lib")
endif()
link_directories("${PADDLE_DIR}/third_party/install/zlib/lib")
link_directories("${PADDLE_DIR}/third_party/install/protobuf/lib")
link_directories("${PADDLE_DIR}/third_party/install/glog/lib")
link_directories("${PADDLE_DIR}/third_party/install/gflags/lib")
link_directories("${PADDLE_DIR}/third_party/install/xxhash/lib")
link_directories("${PADDLE_DIR}/paddle/lib/")
link_directories("${CMAKE_CURRENT_BINARY_DIR}")
if (WIN32)
include_directories("${PADDLE_DIR}/paddle/fluid/inference")
include_directories("${PADDLE_DIR}/paddle/include")
link_directories("${PADDLE_DIR}/paddle/fluid/inference")
include_directories("${OPENCV_DIR}/build/include")
include_directories("${OPENCV_DIR}/opencv/build/include")
link_directories("${OPENCV_DIR}/build/x64/vc14/lib")
else ()
include_directories("${PADDLE_DIR}/paddle/include")
link_directories("${PADDLE_DIR}/paddle/lib")
include_directories("${OPENCV_DIR}/include")
link_directories("${OPENCV_DIR}/lib64")
endif ()
if (WIN32)
add_definitions("/DGOOGLE_GLOG_DLL_DECL=")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /bigobj /MTd")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /bigobj /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj /MTd")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /bigobj /MT")
if (WITH_STATIC_LIB)
safe_set_static_flag()
add_definitions(-DSTATIC_LIB)
endif()
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -o2 -fopenmp -std=c++11")
set(CMAKE_STATIC_LIBRARY_PREFIX "")
endif()
# TODO let users define cuda lib path
if (WITH_GPU)
if (NOT DEFINED CUDA_LIB OR ${CUDA_LIB} STREQUAL "")
message(FATAL_ERROR "please set CUDA_LIB with -DCUDA_LIB=/path/cuda-8.0/lib64")
endif()
if (NOT WIN32)
if (NOT DEFINED CUDNN_LIB)
message(FATAL_ERROR "please set CUDNN_LIB with -DCUDNN_LIB=/path/cudnn_v7.4/cuda/lib64")
endif()
endif(NOT WIN32)
endif()
if (NOT WIN32)
if (USE_TENSORRT AND WITH_GPU)
include_directories("${PADDLE_DIR}/third_party/install/tensorrt/include")
link_directories("${PADDLE_DIR}/third_party/install/tensorrt/lib")
endif()
endif(NOT WIN32)
if (NOT WIN32)
set(NGRAPH_PATH "${PADDLE_DIR}/third_party/install/ngraph")
if(EXISTS ${NGRAPH_PATH})
include(GNUInstallDirs)
include_directories("${NGRAPH_PATH}/include")
link_directories("${NGRAPH_PATH}/${CMAKE_INSTALL_LIBDIR}")
set(NGRAPH_LIB ${NGRAPH_PATH}/${CMAKE_INSTALL_LIBDIR}/libngraph${CMAKE_SHARED_LIBRARY_SUFFIX})
endif()
endif()
if(WITH_MKL)
include_directories("${PADDLE_DIR}/third_party/install/mklml/include")
if (WIN32)
set(MATH_LIB ${PADDLE_DIR}/third_party/install/mklml/lib/mklml.lib
${PADDLE_DIR}/third_party/install/mklml/lib/libiomp5md.lib)
else ()
set(MATH_LIB ${PADDLE_DIR}/third_party/install/mklml/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX}
${PADDLE_DIR}/third_party/install/mklml/lib/libiomp5${CMAKE_SHARED_LIBRARY_SUFFIX})
execute_process(COMMAND cp -r ${PADDLE_DIR}/third_party/install/mklml/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX} /usr/lib)
endif ()
set(MKLDNN_PATH "${PADDLE_DIR}/third_party/install/mkldnn")
if(EXISTS ${MKLDNN_PATH})
include_directories("${MKLDNN_PATH}/include")
if (WIN32)
set(MKLDNN_LIB ${MKLDNN_PATH}/lib/mkldnn.lib)
else ()
set(MKLDNN_LIB ${MKLDNN_PATH}/lib/libmkldnn.so.0)
endif ()
endif()
else()
set(MATH_LIB ${PADDLE_DIR}/third_party/install/openblas/lib/libopenblas${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
if (WIN32)
if(EXISTS "${PADDLE_DIR}/paddle/fluid/inference/libpaddle_fluid${CMAKE_STATIC_LIBRARY_SUFFIX}")
set(DEPS
${PADDLE_DIR}/paddle/fluid/inference/libpaddle_fluid${CMAKE_STATIC_LIBRARY_SUFFIX})
else()
set(DEPS
${PADDLE_DIR}/paddle/lib/libpaddle_fluid${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
endif()
if(WITH_STATIC_LIB)
set(DEPS
${PADDLE_DIR}/paddle/lib/libpaddle_fluid${CMAKE_STATIC_LIBRARY_SUFFIX})
else()
set(DEPS
${PADDLE_DIR}/paddle/lib/libpaddle_fluid${CMAKE_SHARED_LIBRARY_SUFFIX})
endif()
if (NOT WIN32)
set(DEPS ${DEPS}
${MATH_LIB} ${MKLDNN_LIB}
glog gflags protobuf z xxhash
)
if(EXISTS "${PADDLE_DIR}/third_party/install/snappystream/lib")
set(DEPS ${DEPS} snappystream)
endif()
if (EXISTS "${PADDLE_DIR}/third_party/install/snappy/lib")
set(DEPS ${DEPS} snappy)
endif()
else()
set(DEPS ${DEPS}
${MATH_LIB} ${MKLDNN_LIB}
opencv_world346 glog gflags_static libprotobuf zlibstatic xxhash)
set(DEPS ${DEPS} libcmt shlwapi)
if (EXISTS "${PADDLE_DIR}/third_party/install/snappy/lib")
set(DEPS ${DEPS} snappy)
endif()
if(EXISTS "${PADDLE_DIR}/third_party/install/snappystream/lib")
set(DEPS ${DEPS} snappystream)
endif()
endif(NOT WIN32)
if(WITH_GPU)
if(NOT WIN32)
if (USE_TENSORRT)
set(DEPS ${DEPS} ${PADDLE_DIR}/third_party/install/tensorrt/lib/libnvinfer${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${PADDLE_DIR}/third_party/install/tensorrt/lib/libnvinfer_plugin${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${CUDNN_LIB}/libcudnn${CMAKE_SHARED_LIBRARY_SUFFIX})
else()
set(DEPS ${DEPS} ${CUDA_LIB}/cudart${CMAKE_STATIC_LIBRARY_SUFFIX} )
set(DEPS ${DEPS} ${CUDA_LIB}/cublas${CMAKE_STATIC_LIBRARY_SUFFIX} )
set(DEPS ${DEPS} ${CUDA_LIB}/cudnn${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
endif()
if (NOT WIN32)
set(DEPS ${DEPS} ${OPENCV_DIR}/lib64/libopencv_imgcodecs${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/lib64/libopencv_imgproc${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/lib64/libopencv_core${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/lib64/libopencv_highgui${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/libIlmImf${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/liblibjasper${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/liblibpng${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/liblibtiff${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/libittnotify${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/liblibjpeg-turbo${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/liblibwebp${CMAKE_STATIC_LIBRARY_SUFFIX})
set(DEPS ${DEPS} ${OPENCV_DIR}/share/OpenCV/3rdparty/lib64/libzlib${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
if (NOT WIN32)
set(EXTERNAL_LIB "-ldl -lrt -lpthread")
set(DEPS ${DEPS} ${EXTERNAL_LIB})
endif()
add_executable(mask_detector main.cc mask_detector.cc)
target_link_libraries(mask_detector ${DEPS})
if (WIN32)
add_custom_command(TARGET mask_detector POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_DIR}/third_party/install/mklml/lib/mklml.dll ./mklml.dll
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_DIR}/third_party/install/mklml/lib/libiomp5md.dll ./libiomp5md.dll
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_DIR}/third_party/install/mkldnn/lib/mkldnn.dll ./mkldnn.dll
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_DIR}/third_party/install/mklml/lib/mklml.dll ./release/mklml.dll
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_DIR}/third_party/install/mklml/lib/libiomp5md.dll ./release/libiomp5md.dll
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PADDLE_DIR}/third_party/install/mkldnn/lib/mkldnn.dll ./release/mkldnn.dll
)
endif()
{
"configurations": [
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"variables": [
{
"name": "CUDA_LIB",
"value": "D:/projects/packages/cuda10_0/lib64",
"type": "PATH"
},
{
"name": "CUDNN_LIB",
"value": "D:/projects/packages/cuda10_0/lib64",
"type": "PATH"
},
{
"name": "OPENCV_DIR",
"value": "D:/projects/packages/opencv3_4_6",
"type": "PATH"
},
{
"name": "PADDLE_DIR",
"value": "D:/projects/packages/fluid_inference1_6_1",
"type": "PATH"
},
{
"name": "CMAKE_BUILD_TYPE",
"value": "Release",
"type": "STRING"
}
]
}
]
}
# PaddleHub口罩人脸识别及分类模型C++预测部署
百度通过 `PaddleHub` 开源了业界首个口罩人脸检测及人类模型,该模型可以有效检测在密集人类区域中携带和未携带口罩的所有人脸,同时判断出是否有佩戴口罩。开发者可以通过 `PaddleHub` 快速体验模型效果、搭建在线服务,还可以导出模型集成到`Windows``Linux`等不同平台的`C++`开发项目中。
本文档主要介绍如何把模型在`Windows``Linux`上完成基于`C++`的预测部署。
主要包含两个步骤:
- [1. PaddleHub导出预测模型](#1-paddlehub导出预测模型)
- [2. C++预测部署编译](#2-c预测部署编译)
## 1. PaddleHub导出预测模型
#### 1.1 安装 `PaddlePaddle` 和 `PaddleHub`
- `PaddlePaddle`的安装:
请点击[官方安装文档](https://paddlepaddle.org.cn/install/quick) 选择适合的方式
- `PaddleHub`的安装: `pip install paddlehub`
#### 1.2 从`PaddleHub`导出预测模型
在有网络访问条件下,执行`python export_model.py`导出两个可用于推理部署的口罩模型
其中`pyramidbox_lite_mobile_mask`为移动版模型, 模型更小,计算量低;
`pyramidbox_lite_server_mask`为服务器版模型,在此推荐该版本模型,精度相对移动版本更高。
成功执行代码后导出的模型路径结构:
```
pyramidbox_lite_server_mask
|
├── mask_detector # 口罩人脸分类模型
| ├── __model__ # 模型文件
│ └── __params__ # 参数文件
|
└── pyramidbox_lite # 口罩人脸检测模型
├── __model__ # 模型文件
└── __params__ # 参数文件
```
## 2. C++预测部署编译
本项目支持在Windows和Linux上编译并部署C++项目,不同平台的编译请参考:
- [Linux 编译](./docs/linux_build.md)
- [Windows 使用 Visual Studio 2019编译](./docs/windows_build.md)
# Linux平台口罩人脸检测及分类模型C++预测部署
## 1. 系统和软件依赖
### 1.1 操作系统及硬件要求
- Ubuntu 14.04 或者 16.04 (其它平台未测试)
- GCC版本4.8.5 ~ 4.9.2
- 支持Intel MKL-DNN的CPU
- NOTE: 如需在Nvidia GPU运行,请自行安装CUDA 9.0 / 10.0 + CUDNN 7.3+ (不支持9.1/10.1版本的CUDA)
### 1.2 下载PaddlePaddle C++预测库
PaddlePaddle C++ 预测库主要分为CPU版本和GPU版本。
其中,GPU 版本支持`CUDA 10.0``CUDA 9.0`:
以下为各版本C++预测库的下载链接:
| 版本 | 链接 |
| ---- | ---- |
| CPU+MKL版 | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.6.3-cpu-avx-mkl/fluid_inference.tgz) |
| CUDA9.0+MKL 版 | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.6.3-gpu-cuda9-cudnn7-avx-mkl/fluid_inference.tgz) |
| CUDA10.0+MKL 版 | [fluid_inference.tgz](https://paddle-inference-lib.bj.bcebos.com/1.6.3-gpu-cuda10-cudnn7-avx-mkl/fluid_inference.tgz) |
更多可用预测库版本,请点击以下链接下载:[C++预测库下载列表](https://paddlepaddle.org.cn/documentation/docs/zh/advanced_usage/deploy/inference/build_and_install_lib_cn.html)
下载并解压, 解压后的 `fluid_inference`目录包含的内容:
```
fluid_inference
├── paddle # paddle核心库和头文件
|
├── third_party # 第三方依赖库和头文件
|
└── version.txt # 版本和编译信息
```
**注意:** 请把解压后的目录放到合适的路径,**该目录路径后续会作为编译依赖**使用。
### 1.2 编译安装 OpenCV
```shell
# 1. 下载OpenCV3.4.6版本源代码
wget -c https://paddleseg.bj.bcebos.com/inference/opencv-3.4.6.zip
# 2. 解压
unzip opencv-3.4.6.zip && cd opencv-3.4.6
# 3. 创建build目录并编译, 这里安装到/root/projects/opencv3目录
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/opencv3 -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DWITH_IPP=OFF -DBUILD_IPP_IW=OFF -DWITH_LAPACK=OFF -DWITH_EIGEN=OFF -DCMAKE_INSTALL_LIBDIR=lib64 -DWITH_ZLIB=ON -DBUILD_ZLIB=ON -DWITH_JPEG=ON -DBUILD_JPEG=ON -DWITH_PNG=ON -DBUILD_PNG=ON -DWITH_TIFF=ON -DBUILD_TIFF=ON
make -j4
make install
```
其中参数 `CMAKE_INSTALL_PREFIX` 参数指定了安装路径, 上述操作完成后,`opencv` 被安装在 `$HOME/opencv3` 目录(用户也可选择其他路径),**该目录后续作为编译依赖**
## 2. 编译与运行
### 2.1 配置编译脚本
cd `PaddleHub/deploy/demo/mask_detector/`
打开文件`linux_build.sh`, 看到以下内容:
```shell
# Paddle 预测库路径
PADDLE_DIR=/PATH/TO/fluid_inference/
# OpenCV 库路径
OPENCV_DIR=/PATH/TO/opencv3gcc4.8/
# 是否使用GPU
WITH_GPU=ON
# CUDA库路径, 仅 WITH_GPU=ON 时设置
CUDA_LIB=/PATH/TO/CUDA_LIB64/
# CUDNN库路径,仅 WITH_GPU=ON 且 CUDA_LIB有效时设置
CUDNN_LIB=/PATH/TO/CUDNN_LIB64/
cd build
cmake .. \
-DWITH_GPU=${WITH_GPU} \
-DPADDLE_DIR=${PADDLE_DIR} \
-DCUDA_LIB=${CUDA_LIB} \
-DCUDNN_LIB=${CUDNN_LIB} \
-DOPENCV_DIR=${OPENCV_DIR} \
-DWITH_STATIC_LIB=OFF
make -j4
```
把上述参数根据实际情况做修改后,运行脚本编译程序:
```shell
sh linux_build.sh
```
### 2.2. 运行和可视化
可执行文件有 **2** 个参数,第一个是前面导出的`inference_model`路径,第二个是需要预测的图片路径。
示例:
```shell
./build/main /PATH/TO/pyramidbox_lite_server_mask/ /PATH/TO/TEST_IMAGE
```
执行程序时会打印检测框的位置与口罩是否佩戴的结果,另外result.jpg文件为检测的可视化结果。
**预测结果示例:**
![output_image](https://paddlehub.bj.bcebos.com/deploy/result.jpg)
# Windows平台口罩人脸检测及分类模型C++预测部署
## 1. 系统和软件依赖
### 1.1 基础依赖
- Windows 10 / Windows Server 2016+ (其它平台未测试)
- Visual Studio 2019 (社区版或专业版均可)
- CUDA 9.0 / 10.0 + CUDNN 7.3+ (不支持9.1/10.1版本的CUDA)
### 1.2 下载OpenCV并设置环境变量
- 在OpenCV官网下载适用于Windows平台的3.4.6版本: [点击下载](https://sourceforge.net/projects/opencvlibrary/files/3.4.6/opencv-3.4.6-vc14_vc15.exe/download)
- 运行下载的可执行文件,将OpenCV解压至合适目录,这里以解压到`D:\projects\opencv`为例
- 把OpenCV动态库加入到系统环境变量
- 此电脑(我的电脑)->属性->高级系统设置->环境变量
- 在系统变量中找到Path(如没有,自行创建),并双击编辑
- 新建,将opencv路径填入并保存,如D:\projects\opencv\build\x64\vc14\bin
**注意:** `OpenCV`的解压目录后续将做为编译配置项使用,所以请放置合适的目录中。
### 1.3 下载PaddlePaddle C++ 预测库
`PaddlePaddle` **C++ 预测库** 主要分为`CPU``GPU`版本, 其中`GPU版本`提供`CUDA 9.0``CUDA 10.0` 支持。
常用的版本如下:
| 版本 | 链接 |
| ---- | ---- |
| CPU+MKL版 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.3/win-infer/mkl/cpu/fluid_inference_install_dir.zip) |
| CUDA9.0+MKL 版 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.3/win-infer/mkl/post97/fluid_inference_install_dir.zip) |
| CUDA10.0+MKL 版 | [fluid_inference_install_dir.zip](https://paddle-wheel.bj.bcebos.com/1.6.3/win-infer/mkl/post107/fluid_inference_install_dir.zip) |
更多不同平台的可用预测库版本,请[点击查看](https://paddlepaddle.org.cn/documentation/docs/zh/advanced_usage/deploy/inference/windows_cpp_inference.html) 选择适合你的版本。
下载并解压, 解压后的 `fluid_inference`目录包含的内容:
```
fluid_inference_install_dir
├── paddle # paddle核心库和头文件
|
├── third_party # 第三方依赖库和头文件
|
└── version.txt # 版本和编译信息
```
**注意:** 这里的`fluid_inference_install_dir` 目录所在路径,将用于后面的编译参数设置,请放置在合适的位置。
## 2. Visual Studio 2019 编译
- 2.1 打开Visual Studio 2019 Community,点击`继续但无需代码`, 如下图:
![step2.1](https://paddleseg.bj.bcebos.com/inference/vs2019_step1.png)
- 2.2 点击 `文件`->`打开`->`CMake`, 如下图:
![step2.2](https://paddleseg.bj.bcebos.com/inference/vs2019_step2.png)
- 2.3 选择本项目根目录`CMakeList.txt`文件打开, 如下图:
![step2.3](https://paddleseg.bj.bcebos.com/deploy/docs/vs2019_step2.3.png)
- 2.4 点击:`项目`->`PaddleMaskDetector的CMake设置`
![step2.4](https://paddleseg.bj.bcebos.com/deploy/docs/vs2019_step2.4.png)
- 2.5 点击浏览设置`OPENCV_DIR`, `CUDA_LIB``PADDLE_DIR` 3个编译依赖库的位置, 设置完成后点击`保存并生成CMake缓存并加载变量`
![step2.5](https://paddleseg.bj.bcebos.com/inference/vs2019_step5.png)
- 2.6 点击`生成`->`全部生成` 编译项目
![step2.6](https://paddleseg.bj.bcebos.com/inference/vs2019_step6.png)
## 3. 运行程序
成功编译后, 产出的可执行文件在项目子目录`out\build\x64-Release`目录, 按以下步骤运行代码:
- 打开`cmd`切换至该目录
- 运行以下命令传入口罩识别模型路径与测试图片
```shell
main.exe ./pyramidbox_lite_server_mask/ ./images/mask_input.png
```
第一个参数即`PaddleHub`导出的预测模型,第二个参数即要预测的图片。
运行后,预测结果保存在文件`result.jpg`中。
**预测结果示例:**
![output_image](https://paddlehub.bj.bcebos.com/deploy/result.jpg)
# Copyright (c) 2020 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 paddlehub as hub
# Load mask detector module from PaddleHub
module = hub.Module(name="pyramidbox_lite_server_mask", version='1.1.0')
# Export inference model for deployment
module.processor.save_inference_model("./pyramidbox_lite_server_mask")
print("pyramidbox_lite_server_mask module export done!")
# Load mask detector (mobile version) module from PaddleHub
module = hub.Module(name="pyramidbox_lite_mobile_mask", version="1.1.0")
# Export inference model for deployment
module.processor.save_inference_model("./pyramidbox_lite_mobile_mask")
print("pyramidbox_lite_mobile_mask module export done!")
WITH_GPU=ON
PADDLE_DIR=/ssd3/chenzeyu01/PaddleMaskDetector/fluid_inference
CUDA_LIB=/home/work/cuda-10.1/lib64/
CUDNN_LIB=/home/work/cudnn/cudnn_v7.4/cuda/lib64/
OPENCV_DIR=/ssd3/chenzeyu01/PaddleMaskDetector/opencv3gcc4.8/
rm -rf build
mkdir -p build
cd build
cmake .. \
-DWITH_GPU=${WITH_GPU} \
-DPADDLE_DIR=${PADDLE_DIR} \
-DCUDA_LIB=${CUDA_LIB} \
-DCUDNN_LIB=${CUDNN_LIB} \
-DOPENCV_DIR=${OPENCV_DIR} \
-DWITH_STATIC_LIB=OFF
make clean
make -j12
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include <string>
#include "mask_detector.h" // NOLINT
int main(int argc, char* argv[]) {
if (argc < 3 || argc > 4) {
std::cout << "Usage:"
<< "./mask_detector ./models/ ./images/test.png"
<< std::endl;
return -1;
}
bool use_gpu = (argc == 4 ? std::stoi(argv[3]) : false);
auto det_model_dir = std::string(argv[1]) + "/pyramidbox_lite";
auto cls_model_dir = std::string(argv[1]) + "/mask_detector";
auto image_path = argv[2];
// Init Detection Model
float det_shrink = 0.6;
float det_threshold = 0.7;
std::vector<float> det_means = {104, 177, 123};
std::vector<float> det_scale = {0.007843, 0.007843, 0.007843};
FaceDetector detector(
det_model_dir,
det_means,
det_scale,
use_gpu,
det_threshold);
// Init Classification Model
std::vector<float> cls_means = {0.5, 0.5, 0.5};
std::vector<float> cls_scale = {1.0, 1.0, 1.0};
MaskClassifier classifier(
cls_model_dir,
cls_means,
cls_scale,
use_gpu);
// Load image
cv::Mat img = imread(image_path, cv::IMREAD_COLOR);
// Prediction result
std::vector<FaceResult> results;
// Stage1: Face detection
detector.Predict(img, &results, det_shrink);
// Stage2: Mask wearing classification
classifier.Predict(&results);
for (const FaceResult& item : results) {
printf("{left=%d, right=%d, top=%d, bottom=%d},"
" class_id=%d, confidence=%.5f\n",
item.rect[0],
item.rect[1],
item.rect[2],
item.rect[3],
item.class_id,
item.confidence);
}
// Visualization result
cv::Mat vis_img;
VisualizeResult(img, results, &vis_img);
cv::imwrite("result.jpg", vis_img);
return 0;
}
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
# include "mask_detector.h"
// Normalize the image by (pix - mean) * scale
void NormalizeImage(
const std::vector<float> &mean,
const std::vector<float> &scale,
cv::Mat& im, // NOLINT
float* input_buffer) {
int height = im.rows;
int width = im.cols;
int stride = width * height;
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
int base = h * width + w;
input_buffer[base + 0 * stride] =
(im.at<cv::Vec3f>(h, w)[0] - mean[0]) * scale[0];
input_buffer[base + 1 * stride] =
(im.at<cv::Vec3f>(h, w)[1] - mean[1]) * scale[1];
input_buffer[base + 2 * stride] =
(im.at<cv::Vec3f>(h, w)[2] - mean[2]) * scale[2];
}
}
}
// Load Model and return model predictor
void LoadModel(
const std::string& model_dir,
bool use_gpu,
std::unique_ptr<paddle::PaddlePredictor>* predictor) {
// Config the model info
paddle::AnalysisConfig config;
config.SetModel(model_dir + "/__model__",
model_dir + "/__params__");
if (use_gpu) {
config.EnableUseGpu(100, 0);
} else {
config.DisableGpu();
}
config.SwitchUseFeedFetchOps(false);
config.SwitchSpecifyInputNames(true);
// Memory optimization
config.EnableMemoryOptim();
*predictor = std::move(CreatePaddlePredictor(config));
}
// Visualiztion MaskDetector results
void VisualizeResult(const cv::Mat& img,
const std::vector<FaceResult>& results,
cv::Mat* vis_img) {
for (int i = 0; i < results.size(); ++i) {
int w = results[i].rect[1] - results[i].rect[0];
int h = results[i].rect[3] - results[i].rect[2];
cv::Rect roi = cv::Rect(results[i].rect[0], results[i].rect[2], w, h);
// Configure color and text size
cv::Scalar roi_color;
std::string text;
if (results[i].class_id == 1) {
text = "MASK: ";
roi_color = cv::Scalar(0, 255, 0);
} else {
text = "NO MASK: ";
roi_color = cv::Scalar(0, 0, 255);
}
text += std::to_string(static_cast<int>(results[i].confidence * 100)) + "%";
int font_face = cv::FONT_HERSHEY_TRIPLEX;
double font_scale = 1.f;
float thickness = 1;
cv::Size text_size = cv::getTextSize(text,
font_face,
font_scale,
thickness,
nullptr);
float new_font_scale = roi.width * font_scale / text_size.width;
text_size = cv::getTextSize(text,
font_face,
new_font_scale,
thickness,
nullptr);
cv::Point origin;
origin.x = roi.x;
origin.y = roi.y;
// Configure text background
cv::Rect text_back = cv::Rect(results[i].rect[0],
results[i].rect[2] - text_size.height,
text_size.width,
text_size.height);
// Draw roi object, text, and background
*vis_img = img;
cv::rectangle(*vis_img, roi, roi_color, 2);
cv::rectangle(*vis_img, text_back, cv::Scalar(225, 225, 225), -1);
cv::putText(*vis_img,
text,
origin,
font_face,
new_font_scale,
cv::Scalar(0, 0, 0),
thickness);
}
}
void FaceDetector::Preprocess(const cv::Mat& image_mat, float shrink) {
// Clone the image : keep the original mat for postprocess
cv::Mat im = image_mat.clone();
cv::resize(im, im, cv::Size(), shrink, shrink, cv::INTER_CUBIC);
im.convertTo(im, CV_32FC3, 1.0);
int rc = im.channels();
int rh = im.rows;
int rw = im.cols;
input_shape_ = {1, rc, rh, rw};
input_data_.resize(1 * rc * rh * rw);
float* buffer = input_data_.data();
NormalizeImage(mean_, scale_, im, input_data_.data());
}
void FaceDetector::Postprocess(
const cv::Mat& raw_mat,
float shrink,
std::vector<FaceResult>* result) {
result->clear();
int rect_num = 0;
int rh = input_shape_[2];
int rw = input_shape_[3];
int total_size = output_data_.size() / 6;
for (int j = 0; j < total_size; ++j) {
// Class id
int class_id = static_cast<int>(round(output_data_[0 + j * 6]));
// Confidence score
float score = output_data_[1 + j * 6];
int xmin = (output_data_[2 + j * 6] * rw) / shrink;
int ymin = (output_data_[3 + j * 6] * rh) / shrink;
int xmax = (output_data_[4 + j * 6] * rw) / shrink;
int ymax = (output_data_[5 + j * 6] * rh) / shrink;
int wd = xmax - xmin;
int hd = ymax - ymin;
if (score > threshold_) {
auto roi = cv::Rect(xmin, ymin, wd, hd) &
cv::Rect(0, 0, rw / shrink, rh / shrink);
// A view ref to original mat
cv::Mat roi_ref(raw_mat, roi);
FaceResult result_item;
result_item.rect = {xmin, xmax, ymin, ymax};
result_item.roi_rect = roi_ref;
result->push_back(result_item);
}
}
}
void FaceDetector::Predict(const cv::Mat& im,
std::vector<FaceResult>* result,
float shrink) {
// Preprocess image
Preprocess(im, shrink);
// Prepare input tensor
auto input_names = predictor_->GetInputNames();
auto in_tensor = predictor_->GetInputTensor(input_names[0]);
in_tensor->Reshape(input_shape_);
in_tensor->copy_from_cpu(input_data_.data());
// Run predictor
predictor_->ZeroCopyRun();
// Get output tensor
auto output_names = predictor_->GetOutputNames();
auto out_tensor = predictor_->GetOutputTensor(output_names[0]);
std::vector<int> output_shape = out_tensor->shape();
// Calculate output length
int output_size = 1;
for (int j = 0; j < output_shape.size(); ++j) {
output_size *= output_shape[j];
}
output_data_.resize(output_size);
out_tensor->copy_to_cpu(output_data_.data());
// Postprocessing result
Postprocess(im, shrink, result);
}
inline void MaskClassifier::Preprocess(std::vector<FaceResult>* faces) {
int batch_size = faces->size();
input_shape_ = {
batch_size,
EVAL_CROP_SIZE_[0],
EVAL_CROP_SIZE_[1],
EVAL_CROP_SIZE_[2]
};
// Reallocate input buffer
int input_size = 1;
for (int x : input_shape_) {
input_size *= x;
}
input_data_.resize(input_size);
auto buffer_base = input_data_.data();
for (int i = 0; i < batch_size; ++i) {
cv::Mat im = (*faces)[i].roi_rect;
// Resize
int rc = im.channels();
int rw = im.cols;
int rh = im.rows;
cv::Size resize_size(input_shape_[3], input_shape_[2]);
if (rw != input_shape_[3] || rh != input_shape_[2]) {
cv::resize(im, im, resize_size, 0.f, 0.f, cv::INTER_CUBIC);
}
im.convertTo(im, CV_32FC3, 1.0 / 256.0);
rc = im.channels();
rw = im.cols;
rh = im.rows;
float* buffer_i = buffer_base + i * rc * rw * rh;
NormalizeImage(mean_, scale_, im, buffer_i);
}
}
void MaskClassifier::Postprocess(std::vector<FaceResult>* faces) {
float* data = output_data_.data();
int batch_size = faces->size();
int out_num = output_data_.size();
for (int i = 0; i < batch_size; ++i) {
auto out_addr = data + (out_num / batch_size) * i;
int best_class_id = 0;
float best_class_score = *(best_class_id + out_addr);
for (int j = 0; j < (out_num / batch_size); ++j) {
auto infer_class = j;
auto score = *(j + out_addr);
if (score > best_class_score) {
best_class_id = infer_class;
best_class_score = score;
}
}
(*faces)[i].class_id = best_class_id;
(*faces)[i].confidence = best_class_score;
}
}
void MaskClassifier::Predict(std::vector<FaceResult>* faces) {
Preprocess(faces);
// Prepare input tensor
auto input_names = predictor_->GetInputNames();
auto in_tensor = predictor_->GetInputTensor(input_names[0]);
in_tensor->Reshape(input_shape_);
in_tensor->copy_from_cpu(input_data_.data());
// Run predictor
predictor_->ZeroCopyRun();
// Get output tensor
auto output_names = predictor_->GetOutputNames();
auto out_tensor = predictor_->GetOutputTensor(output_names[0]);
std::vector<int> output_shape = out_tensor->shape();
// Calculate output length
int output_size = 1;
for (int j = 0; j < output_shape.size(); ++j) {
output_size *= output_shape[j];
}
output_data_.resize(output_size);
out_tensor->copy_to_cpu(output_data_.data());
Postprocess(faces);
}
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <utility>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "paddle_inference_api.h" // NOLINT
// MaskDetector Result
struct FaceResult {
// Detection result: face rectangle
std::vector<int> rect;
// Detection result: cv::Mat of face rectange
cv::Mat roi_rect;
// Classification result: confidence
float confidence;
// Classification result : class id
int class_id;
};
// Load Paddle Inference Model
void LoadModel(
const std::string& model_dir,
bool use_gpu,
std::unique_ptr<paddle::PaddlePredictor>* predictor);
// Visualiztion MaskDetector results
void VisualizeResult(const cv::Mat& img,
const std::vector<FaceResult>& results,
cv::Mat* vis_img);
class FaceDetector {
public:
explicit FaceDetector(const std::string& model_dir,
const std::vector<float>& mean,
const std::vector<float>& scale,
bool use_gpu = false,
float threshold = 0.7) :
mean_(mean),
scale_(scale),
threshold_(threshold) {
LoadModel(model_dir, use_gpu, &predictor_);
}
// Run predictor
void Predict(
const cv::Mat& img,
std::vector<FaceResult>* result,
float shrink);
private:
// Preprocess image and copy data to input buffer
void Preprocess(const cv::Mat& image_mat, float shrink);
// Postprocess result
void Postprocess(
const cv::Mat& raw_mat,
float shrink,
std::vector<FaceResult>* result);
std::unique_ptr<paddle::PaddlePredictor> predictor_;
std::vector<float> input_data_;
std::vector<float> output_data_;
std::vector<int> input_shape_;
std::vector<float> mean_;
std::vector<float> scale_;
float threshold_;
};
class MaskClassifier {
public:
explicit MaskClassifier(const std::string& model_dir,
const std::vector<float>& mean,
const std::vector<float>& scale,
bool use_gpu = false) :
mean_(mean),
scale_(scale) {
LoadModel(model_dir, use_gpu, &predictor_);
}
void Predict(std::vector<FaceResult>* faces);
private:
void Preprocess(std::vector<FaceResult>* faces);
void Postprocess(std::vector<FaceResult>* faces);
std::unique_ptr<paddle::PaddlePredictor> predictor_;
std::vector<float> input_data_;
std::vector<int> input_shape_;
std::vector<float> output_data_;
const std::vector<int> EVAL_CROP_SIZE_ = {3, 128, 128};
std::vector<float> mean_;
std::vector<float> scale_;
};
# -*- coding:utf-8 -*-
import paddlehub as hub
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import json
import os
module = hub.Module(name="pyramidbox_lite_server_mask")
# opencv输出中文
def paint_chinese(im, chinese, position, fontsize, color_bgr):
# 图像从OpenCV格式转换成PIL格式
img_PIL = Image.fromarray(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))
font = ImageFont.truetype(
'SourceHanSansSC-Medium.otf', fontsize, encoding="utf-8")
#color = (255,0,0) # 字体颜色
#position = (100,100)# 文字输出位置
color = color_bgr[::-1]
draw = ImageDraw.Draw(img_PIL)
# PIL图片上打印汉字 # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体
draw.text(position, chinese, font=font, fill=color)
img = cv2.cvtColor(np.asarray(img_PIL), cv2.COLOR_RGB2BGR) # PIL图片转cv2 图片
return img
result_path = './result'
if not os.path.exists(result_path):
os.mkdir(result_path)
name = "./result/1-mask_detection.mp4"
width = 1280
height = 720
fps = 30
fourcc = cv2.VideoWriter_fourcc(*'vp90')
writer = cv2.VideoWriter(name, fourcc, fps, (width, height))
maskIndex = 0
index = 0
data = []
capture = cv2.VideoCapture(0) # 打开摄像头
#capture = cv2.VideoCapture('./test_video.mp4') # 打开视频文件
while True:
frameData = {}
ret, frame = capture.read() # frame即视频的一帧数据
if ret == False:
break
frame_copy = frame.copy()
input_dict = {"data": [frame]}
results = module.face_detection(data=input_dict)
maskFrameDatas = []
for result in results:
label = result['data']['label']
confidence_origin = result['data']['confidence']
confidence = round(confidence_origin, 2)
confidence_desc = str(confidence)
top, right, bottom, left = int(result['data']['top']), int(
result['data']['right']), int(result['data']['bottom']), int(
result['data']['left'])
#将当前帧保存为图片
img_name = "avatar_%d.png" % (maskIndex)
path = "./result/" + img_name
image = frame[top - 10:bottom + 10, left - 10:right + 10]
cv2.imwrite(path, image, [int(cv2.IMWRITE_PNG_COMPRESSION), 9])
maskFrameData = {}
maskFrameData['top'] = top
maskFrameData['right'] = right
maskFrameData['bottom'] = bottom
maskFrameData['left'] = left
maskFrameData['confidence'] = float(confidence_origin)
maskFrameData['label'] = label
maskFrameData['img'] = img_name
maskFrameDatas.append(maskFrameData)
maskIndex += 1
color = (0, 255, 0)
label_cn = "有口罩"
if label == 'NO MASK':
color = (0, 0, 255)
label_cn = "无口罩"
cv2.rectangle(frame_copy, (left, top), (right, bottom), color, 3)
cv2.putText(frame_copy, label, (left, top - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
#origin_point = (left, top - 36)
#frame_copy = paint_chinese(frame_copy, label_cn, origin_point, 24,
# color)
writer.write(frame_copy)
cv2.imshow('Mask Detection', frame_copy)
frameData['frame'] = index
# frameData['seconds'] = int(index/fps)
frameData['data'] = maskFrameDatas
data.append(frameData)
print(json.dumps(frameData))
index += 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
with open("./result/2-mask_detection.json", "w") as f:
json.dump(data, f)
writer.release()
cv2.destroyAllWindows()
# 口罩佩戴检测模型Python高性能部署方案
百度通过 PaddleHub 开源了业界首个口罩人脸检测及人类模型,该模型可以有效检测在密集人类区域中携带和未携带口罩的所有人脸,同时判断出是否有佩戴口罩。开发者可以通过 PaddleHub 快速体验模型效果、搭建在线服务。
本文档主要介绍如何完成基于`python`的口罩佩戴检测预测。
主要包含两个步骤:
- [1. PaddleHub导出预测模型](#1-paddlehub导出预测模型)
- [2. 基于python的预测](#2-预测部署编译)
## 1. PaddleHub导出预测模型
#### 1.1 安装 `PaddlePaddle` 和 `PaddleHub`
- `PaddlePaddle`的安装:
请点击[官方安装文档](https://paddlepaddle.org.cn/install/quick) 选择适合的方式
- `PaddleHub`的安装: `pip install paddlehub`
- `opencv`的安装: `pip install opencv-python`
#### 1.2 从`PaddleHub`导出预测模型
```
git clone https://github.com/PaddlePaddle/PaddleHub.git
cd PaddleHub/demo/mask_detection/python/
python export_model.py
```
在有网络访问条件下,执行`python export_model.py`导出两个可用于推理部署的口罩模型
其中`pyramidbox_lite_mobile_mask`为移动版模型, 模型更小,计算量低;
`pyramidbox_lite_server_mask`为服务器版模型,在此推荐该版本模型,精度相对移动版本更高。
成功执行代码后导出的模型路径结构:
```
pyramidbox_lite_server_mask
|
├── mask_detector # 口罩人脸分类模型
| ├── __model__ # 模型文件
│ └── __params__ # 参数文件
|
└── pyramidbox_lite # 口罩人脸检测模型
├── __model__ # 模型文件
└── __params__ # 参数文件
```
## 2. 基于python的预测
### 2.1 执行预测程序
在终端输入以下命令进行预测:
```bash
python infer.py --models_dir=/path/to/models --img_paths=/path/to/images --video_path=/path/to/video --video_size=size/of/video --use_camera=(False/True)
--use_gpu=(False/True)
```
参数说明如下:
| 参数 | 是否必须|含义 |
|-------|-------|----------|
| models_dir | Yes|上述导出的模型路径 |
| img_paths |img_paths/video_path 二选一|需要预测的图片目录 |
| video_path |img_paths/video_path 二选一|需要预测的视频目录|
| use_camera |No|是否打开摄像头进行预测,默认为False |
| open_imshow |No|是否对视频的检测结果实时绘图,默认为False |
| use_gpu |No|是否GPU,默认为False|
说明:
如果use_gpu=True,请先在命令行指定GPU,如:
```
export CUDA_VISIBLE_DEVICES=0
```
## 3. 可视化结果
执行完预测后,预测的可视化结果会保存在当前路径下的`./result/`下面。
输入样例:
![avatar](./images/mask.jpg)
输出结果:
![avatar](./images/mask.jpg.result.jpg)
# Copyright (c) 2020 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 paddlehub as hub
# Load mask detector module from PaddleHub
module = hub.Module(name="pyramidbox_lite_server_mask", version='1.1.0')
# Export inference model for deployment
module.processor.save_inference_model("./pyramidbox_lite_server_mask")
print("pyramidbox_lite_server_mask module export done!")
# Load mask detector (mobile version) module from PaddleHub
module = hub.Module(name="pyramidbox_lite_mobile_mask", version="1.1.0")
# Export inference model for deployment
module.processor.save_inference_model("./pyramidbox_lite_mobile_mask")
print("pyramidbox_lite_mobile_mask module export done!")
# coding: utf8
# copyright (c) 2019 PaddlePaddle Authors. All Rights Reserve.
#
# 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 sys
import ast
import time
import json
import argparse
import numpy as np
import cv2
import paddle.fluid as fluid
from PIL import Image
from PIL import ImageDraw
import argparse
def parse_args():
parser = argparse.ArgumentParser('mask detection.')
parser.add_argument(
'--models_dir', type=str, default='', help='path of models.')
parser.add_argument(
'--img_paths', type=str, default='', help='path of images')
parser.add_argument(
'--video_path', type=str, default='', help='path of video.')
parser.add_argument(
'--use_camera',
type=bool,
default=False,
help='switch detect video or camera, default:video.')
parser.add_argument(
'--open_imshow',
type=bool,
default=False,
help='visualize video detection results in real time.')
parser.add_argument(
'--use_gpu',
type=bool,
default=False,
help='switch cpu/gpu, default:cpu.')
args = parser.parse_args()
return args
class FaceResult:
def __init__(self, rect_data, rect_info):
self.rect_info = rect_info
self.rect_data = rect_data
self.class_id = -1
self.score = 0.0
def VisualizeResult(im, faces):
LABELS = ['NO_MASK', 'MASK']
COLORS = [(0, 0, 255), (0, 255, 0)]
for face in faces:
label = LABELS[face.class_id]
color = COLORS[face.class_id]
left, right, top, bottom = [int(item) for item in face.rect_info]
label_position = (left, top)
cv2.putText(im, label, label_position, cv2.FONT_HERSHEY_SIMPLEX, 1,
color, 2, cv2.LINE_AA)
cv2.rectangle(im, (left, top), (right, bottom), color, 3)
return im
def LoadModel(model_dir, use_gpu=False):
config = fluid.core.AnalysisConfig(model_dir + '/__model__',
model_dir + '/__params__')
if use_gpu:
config.enable_use_gpu(100, 0)
config.switch_ir_optim(True)
else:
config.disable_gpu()
config.disable_glog_info()
config.switch_specify_input_names(True)
config.enable_memory_optim()
return fluid.core.create_paddle_predictor(config)
class MaskClassifier:
def __init__(self, model_dir, mean, scale, use_gpu=False):
self.mean = np.array(mean).reshape((3, 1, 1))
self.scale = np.array(scale).reshape((3, 1, 1))
self.predictor = LoadModel(model_dir, use_gpu)
self.EVAL_SIZE = (128, 128)
def Preprocess(self, faces):
h, w = self.EVAL_SIZE[1], self.EVAL_SIZE[0]
inputs = []
for face in faces:
im = cv2.resize(
face.rect_data, (128, 128),
fx=0,
fy=0,
interpolation=cv2.INTER_CUBIC)
# HWC -> CHW
im = im.swapaxes(1, 2)
im = im.swapaxes(0, 1)
# Convert to float
im = im[:, :, :].astype('float32') / 256.0
# im = (im - mean) * scale
im = im - self.mean
im = im * self.scale
im = im[np.newaxis, :, :, :]
inputs.append(im)
return inputs
def Postprocess(self, output_data, faces):
argmx = np.argmax(output_data, axis=1)
for idx in range(len(faces)):
faces[idx].class_id = argmx[idx]
faces[idx].score = output_data[idx][argmx[idx]]
return faces
def Predict(self, faces):
inputs = self.Preprocess(faces)
if len(inputs) != 0:
input_data = np.concatenate(inputs)
im_tensor = fluid.core.PaddleTensor(
input_data.copy().astype('float32'))
output_data = self.predictor.run([im_tensor])[0]
output_data = output_data.as_ndarray()
self.Postprocess(output_data, faces)
class FaceDetector:
def __init__(self, model_dir, mean, scale, use_gpu=False, threshold=0.7):
self.mean = np.array(mean).reshape((3, 1, 1))
self.scale = np.array(scale).reshape((3, 1, 1))
self.threshold = threshold
self.predictor = LoadModel(model_dir, use_gpu)
def Preprocess(self, image, shrink):
h, w = int(image.shape[1] * shrink), int(image.shape[0] * shrink)
im = cv2.resize(
image, (h, w), fx=0, fy=0, interpolation=cv2.INTER_CUBIC)
# HWC -> CHW
im = im.swapaxes(1, 2)
im = im.swapaxes(0, 1)
# Convert to float
im = im[:, :, :].astype('float32')
# im = (im - mean) * scale
im = im - self.mean
im = im * self.scale
im = im[np.newaxis, :, :, :]
return im
def Postprocess(self, output_data, ori_im, shrink):
det_out = []
h, w = ori_im.shape[0], ori_im.shape[1]
for out in output_data:
class_id = int(out[0])
score = out[1]
xmin = (out[2] * w)
ymin = (out[3] * h)
xmax = (out[4] * w)
ymax = (out[5] * h)
wd = xmax - xmin
hd = ymax - ymin
valid = (xmax >= xmin and xmin > 0 and ymax >= ymin and ymin > 0)
if score > self.threshold and valid:
roi_rect = ori_im[int(ymin):int(ymax), int(xmin):int(xmax)]
det_out.append(FaceResult(roi_rect, [xmin, xmax, ymin, ymax]))
return det_out
def Predict(self, image, shrink):
ori_im = image.copy()
im = self.Preprocess(image, shrink)
im_tensor = fluid.core.PaddleTensor(im.copy().astype('float32'))
output_data = self.predictor.run([im_tensor])[0]
output_data = output_data.as_ndarray()
return self.Postprocess(output_data, ori_im, shrink)
def predict_images(args):
detector = FaceDetector(
model_dir=args.models_dir + '/pyramidbox_lite/',
mean=[104.0, 177.0, 123.0],
scale=[0.007843, 0.007843, 0.007843],
use_gpu=args.use_gpu,
threshold=0.7)
classifier = MaskClassifier(
model_dir=args.models_dir + '/mask_detector/',
mean=[0.5, 0.5, 0.5],
scale=[1.0, 1.0, 1.0],
use_gpu=args.use_gpu)
names = []
image_paths = []
for name in os.listdir(args.img_paths):
if name.split('.')[-1] in ['jpg', 'png', 'jpeg']:
names.append(name)
image_paths.append(os.path.join(args.img_paths, name))
images = [cv2.imread(path, cv2.IMREAD_COLOR) for path in image_paths]
path = './result'
isExists = os.path.exists(path)
if not isExists:
os.makedirs(path)
for idx in range(len(images)):
im = images[idx]
det_out = detector.Predict(im, shrink=0.7)
classifier.Predict(det_out)
img = VisualizeResult(im, det_out)
cv2.imwrite(os.path.join(path, names[idx] + '.result.jpg'), img)
def predict_video(args, im_shape=(1920, 1080), use_camera=False):
if args.use_camera:
capture = cv2.VideoCapture(0)
else:
capture = cv2.VideoCapture(args.video_path)
detector = FaceDetector(
model_dir=args.models_dir + '/pyramidbox_lite/',
mean=[104.0, 177.0, 123.0],
scale=[0.007843, 0.007843, 0.007843],
use_gpu=args.use_gpu,
threshold=0.7)
classifier = MaskClassifier(
model_dir=args.models_dir + '/mask_detector/',
mean=[0.5, 0.5, 0.5],
scale=[1.0, 1.0, 1.0],
use_gpu=args.use_gpu)
path = './result'
isExists = os.path.exists(path)
if not isExists:
os.makedirs(path)
fps = 30
width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
writer = cv2.VideoWriter(
os.path.join(path, 'result.mp4'), fourcc, fps, (width, height))
import time
start_time = time.time()
index = 0
while (1):
ret, frame = capture.read()
if not ret:
break
print('detect frame:%d' % (index))
index += 1
det_out = detector.Predict(frame, shrink=0.5)
classifier.Predict(det_out)
end_pre = time.time()
im = VisualizeResult(frame, det_out)
writer.write(im)
if args.open_imshow:
cv2.imshow('Mask Detection', im)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
end_time = time.time()
print("Average prediction time per frame:", (end_time - start_time) / index)
writer.release()
if __name__ == "__main__":
args = parse_args()
print(args.models_dir)
if args.img_paths != '':
predict_images(args)
elif args.video_path != '' or args.use_camera:
predict_video(args)
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册