Skip to content

Commit df3451a

Browse files
committed
Use wrapped function api and add inference benchmark
1 parent 4d8cbc4 commit df3451a

File tree

10 files changed

+333
-72
lines changed

10 files changed

+333
-72
lines changed

deploy/cpp/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# PaddleSeg C++ 预测部署方案
22

3-
## 使用Paddle Inference部署PaddleSeg模型
3+
## 使用Paddle Inference C++部署PaddleSeg模型
44

5-
使用Paddle Inference部署PaddleSeg模型,请参考[教程](../../docs/deployment/inference/cpp_inference.md)
5+
使用Paddle Inference C++部署PaddleSeg模型,请参考[教程](../../docs/deployment/inference/cpp_inference.md)
66

77
## 使用PaddleX部署PaddleSeg模型
88

deploy/python/README.md

+1-46
Original file line numberDiff line numberDiff line change
@@ -1,46 +1 @@
1-
# PaddleSeg Python 预测部署方案
2-
3-
## 1. 说明
4-
5-
本文档介绍使用飞桨推理的Python接口在服务器端部署分割模型。大家通过一定的配置,加上少量的代码,即可把模型集成到自己的服务中,完成图像分割的任务。
6-
7-
飞桨推理的[官网文档](https://paddleinference.paddlepaddle.org.cn/product_introduction/summary.html)介绍了部署模型的步骤、多种API接口、示例等等,大家可以根据实际需求进行使用。
8-
9-
## 2. 前置准备
10-
11-
请使用[模型导出工具](../../docs/model_export.md)导出您的模型, 或点击下载我们的[样例模型](https://paddleseg.bj.bcebos.com/dygraph/demo/bisenet_demo_model.tar.gz)用于测试。
12-
13-
接着准备一张测试图片用于试验效果,我们提供了cityscapes验证集中的一张[图片](https://paddleseg.bj.bcebos.com/dygraph/demo/cityscapes_demo.png)用于演示效果,如果您的模型是使用其他数据集训练的,请自行准备测试图片。
14-
15-
## 3. 预测
16-
17-
在终端输入以下命令进行预测:
18-
```shell
19-
python deploy/python/infer.py --config /path/to/deploy.yaml --image_path /path/to/image/path/or/dir
20-
```
21-
22-
参数说明如下:
23-
|参数名|用途|是否必选项|默认值|
24-
|-|-|-|-|
25-
|config|**导出模型时生成的配置文件**, 而非configs目录下的配置文件||-|
26-
|image_path|预测图片的路径或者目录或者文件列表||-|
27-
|batch_size|单卡batch size||1|
28-
|save_dir|保存预测结果的目录||output|
29-
|device|预测执行设备,可选项有'cpu','gpu'||'gpu'|
30-
|use_trt|是否开启TensorRT来加速预测||False|
31-
|precision|启动TensorRT预测时的数值精度,可选项有'fp32','fp16','int8'||'fp32'|
32-
|cpu_threads|使用cpu预测的线程数||10|
33-
|enable_mkldnn|是否使用MKL-DNN加速cpu预测||False|
34-
|benchmark|是否产出日志,包含环境、模型、配置、性能信息||False|
35-
|with_argmax|对预测结果进行argmax操作|||
36-
37-
*测试样例和预测结果如下*
38-
![cityscape_predict_demo.png](../../docs/images/cityscapes_predict_demo.png)
39-
40-
**注意**
41-
42-
1. 当使用量化模型预测时,需要同时开启TensorRT预测和int8预测才会有加速效果
43-
44-
2. 使用TensorRT需要使用支持TRT功能的Paddle库,请参考[附录](https://www.paddlepaddle.org.cn/documentation/docs/zh/install/Tables.html#whl-release)下载对应的PaddlePaddle安装包,或者参考[源码编译](https://www.paddlepaddle.org.cn/documentation/docs/zh/install/compile/fromsource.html)自行编译
45-
46-
3. 要开启`--benchmark`的话需要安装auto_log。[安装方式](https://github.com/LDOUBLEV/AutoLog)
1+
使用Paddle Inference Python部署PaddleSeg模型,请参考[教程](../../docs/deployment/inference/python_inference.md)

deploy/python/infer.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def __init__(self, args):
7575
if args.device == 'gpu':
7676
# set GPU configs accordingly
7777
# such as intialize the gpu memory, enable tensorrt
78+
logger.info("Use GPU")
7879
pred_cfg.enable_use_gpu(100, 0)
7980
pred_cfg.switch_ir_optim(True)
8081
precision_map = {
@@ -100,6 +101,7 @@ def __init__(self, args):
100101
else:
101102
# set CPU configs accordingly,
102103
# such as enable_mkldnn, set_cpu_math_library_num_threads
104+
logger.info("Use CPU")
103105
pred_cfg.disable_gpu()
104106
if args.enable_mkldnn:
105107
# cache 10 different shapes for mkldnn to avoid memory leak
@@ -109,7 +111,7 @@ def __init__(self, args):
109111

110112
self.predictor = create_predictor(pred_cfg)
111113

112-
if args.benchmark:
114+
if hasattr(self.args, 'benchmark') and self.args.benchmark:
113115
import auto_log
114116
pid = os.getpid()
115117
self.autolog = auto_log.AutoLogger(

deploy/python/infer_benchmark.py

+207
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import argparse
16+
import codecs
17+
import os
18+
import sys
19+
20+
import time
21+
import yaml
22+
import numpy as np
23+
import paddle
24+
25+
LOCAL_PATH = os.path.dirname(os.path.abspath(__file__))
26+
sys.path.append(os.path.join(LOCAL_PATH, '..', '..'))
27+
28+
from paddleseg.cvlibs import manager
29+
from paddleseg.utils import logger, metrics, progbar
30+
31+
from infer import Predictor
32+
33+
34+
def parse_args():
35+
parser = argparse.ArgumentParser(description='Model Infer')
36+
parser.add_argument(
37+
"--config",
38+
dest="cfg",
39+
help="The config file.",
40+
default=None,
41+
type=str,
42+
required=True)
43+
44+
parser.add_argument(
45+
'--dataset_type',
46+
dest='dataset_type',
47+
help='The name of dataset, such as Cityscapes, PascalVOC and ADE20K.',
48+
type=str,
49+
default=None,
50+
required=True)
51+
parser.add_argument(
52+
'--dataset_path',
53+
dest='dataset_path',
54+
help='The directory of the dataset to be predicted. If set dataset_path, '
55+
'it use the test and label images to calculate the mIoU.',
56+
type=str,
57+
default=None,
58+
required=True)
59+
parser.add_argument(
60+
'--dataset_mode',
61+
dest='dataset_mode',
62+
help='The dataset mode, such as train, val.',
63+
type=str,
64+
default="val")
65+
parser.add_argument(
66+
'--batch_size',
67+
dest='batch_size',
68+
help='Mini batch size of one gpu or cpu.',
69+
type=int,
70+
default=1)
71+
72+
parser.add_argument(
73+
'--device',
74+
choices=['cpu', 'gpu'],
75+
default="gpu",
76+
help="Select which device to inference, defaults to gpu.")
77+
78+
parser.add_argument(
79+
'--use_trt',
80+
default=False,
81+
type=eval,
82+
choices=[True, False],
83+
help='Whether to use Nvidia TensorRT to accelerate prediction.')
84+
parser.add_argument(
85+
"--precision",
86+
default="fp32",
87+
type=str,
88+
choices=["fp32", "fp16", "int8"],
89+
help='The tensorrt precision.')
90+
91+
parser.add_argument(
92+
'--cpu_threads',
93+
default=10,
94+
type=int,
95+
help='Number of threads to predict when using cpu.')
96+
parser.add_argument(
97+
'--enable_mkldnn',
98+
default=False,
99+
type=eval,
100+
choices=[True, False],
101+
help='Enable to use mkldnn to speed up when using cpu.')
102+
103+
parser.add_argument(
104+
'--with_argmax',
105+
dest='with_argmax',
106+
help='Perform argmax operation on the predict result.',
107+
action='store_true')
108+
109+
parser.add_argument(
110+
'--print_detail',
111+
dest='print_detail',
112+
help='Print GLOG information of Paddle Inference.',
113+
action='store_true')
114+
115+
return parser.parse_args()
116+
117+
118+
class DatasetPredictor(Predictor):
119+
def __init__(self, args):
120+
super().__init__(args)
121+
122+
def test_dataset(self):
123+
"""
124+
Read the data from dataset and calculate the accurary of the inference model.
125+
"""
126+
comp = manager.DATASETS
127+
if self.args.dataset_type not in comp.components_dict:
128+
raise RuntimeError("The dataset is not supported.")
129+
kwargs = {
130+
'transforms': self.cfg.transforms.transforms,
131+
'dataset_root': self.args.dataset_path,
132+
'mode': self.args.dataset_mode
133+
}
134+
dataset = comp[self.args.dataset_type](**kwargs)
135+
136+
input_names = self.predictor.get_input_names()
137+
input_handle = self.predictor.get_input_handle(input_names[0])
138+
output_names = self.predictor.get_output_names()
139+
output_handle = self.predictor.get_output_handle(output_names[0])
140+
141+
intersect_area_all = 0
142+
pred_area_all = 0
143+
label_area_all = 0
144+
total_time = 0
145+
progbar_val = progbar.Progbar(target=len(dataset), verbose=1)
146+
147+
for idx, (img, label) in enumerate(dataset):
148+
data = np.array([img])
149+
input_handle.reshape(data.shape)
150+
input_handle.copy_from_cpu(data)
151+
152+
start_time = time.time()
153+
self.predictor.run()
154+
end_time = time.time()
155+
total_time += (end_time - start_time)
156+
157+
pred = output_handle.copy_to_cpu()
158+
pred = self.postprocess(paddle.to_tensor(pred))
159+
label = paddle.to_tensor(label, dtype="int32")
160+
161+
intersect_area, pred_area, label_area = metrics.calculate_area(
162+
pred,
163+
label,
164+
dataset.num_classes,
165+
ignore_index=dataset.ignore_index)
166+
167+
intersect_area_all = intersect_area_all + intersect_area
168+
pred_area_all = pred_area_all + pred_area
169+
label_area_all = label_area_all + label_area
170+
171+
progbar_val.update(idx + 1)
172+
173+
class_iou, miou = metrics.mean_iou(intersect_area_all, pred_area_all,
174+
label_area_all)
175+
class_acc, acc = metrics.accuracy(intersect_area_all, pred_area_all)
176+
kappa = metrics.kappa(intersect_area_all, pred_area_all, label_area_all)
177+
178+
logger.info(
179+
"[EVAL] #Images: {} mIoU: {:.4f} Acc: {:.4f} Kappa: {:.4f} ".format(
180+
len(dataset), miou, acc, kappa))
181+
logger.info("[EVAL] Class IoU: \n" + str(np.round(class_iou, 4)))
182+
logger.info("[EVAL] Class Acc: \n" + str(np.round(class_acc, 4)))
183+
logger.info("[EVAL] Average time: %.3f second/img" %
184+
(total_time / len(dataset)))
185+
186+
187+
def main(args):
188+
predictor = DatasetPredictor(args)
189+
if args.dataset_type and args.dataset_path:
190+
predictor.test_dataset()
191+
else:
192+
raise RuntimeError("Please set dataset_type and dataset_path.")
193+
194+
195+
if __name__ == '__main__':
196+
"""
197+
Based on the infer config and dataset, this program read the test and
198+
label images, applys the transfors, run the predictor, ouput the accuracy.
199+
200+
For example:
201+
python deploy/python/infer_benchmark.py \
202+
--config path/to/bisenetv2/deploy.yaml \
203+
--dataset_type Cityscapes \
204+
--dataset_path path/to/cityscapes
205+
"""
206+
args = parse_args()
207+
main(args)

docs/slim/quant/quant.md

+10-12
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,18 @@ PaddleSeg基于PaddleSlim,集成了量化训练(QAT)方法,特点如下
1212

1313
## 1 环境准备
1414

15-
首先,请确保准备好PaddleSeg的基础环境。大家可以在PaddleSeg根目录执行如下命令,如果在`PaddleSeg/output`文件夹中出现预测结果,则证明安装成功
15+
请参考[安装文档](../../install.md)准备好PaddleSeg的基础环境,测试是否安装成功
1616

17-
```
18-
python predict.py \
19-
--config configs/quick_start/bisenet_optic_disc_512x512_1k.yml \
20-
--model_path https://bj.bcebos.com/paddleseg/dygraph/optic_disc/bisenet_optic_disc_512x512_1k/model.pdparams\
21-
--image_path docs/images/optic_test_image.jpg \
22-
--save_dir output/result
23-
```
24-
25-
然后,大家需要再安装最新版本的PaddleSlim。
17+
安装PaddleSlim。
2618

2719
```shell
28-
pip install paddleslim -i https://pypi.tuna.tsinghua.edu.cn/simple
20+
git clone https://github.com/PaddlePaddle/PaddleSlim.git
21+
22+
# 切换到特定commit id
23+
git reset --hard 15ef0c7dcee5a622787b7445f21ad9d1dea0a933
24+
25+
# 安装
26+
python setup.py install
2927
```
3028

3129
## 2 产出量化模型
@@ -40,7 +38,7 @@ pip install paddleslim -i https://pypi.tuna.tsinghua.edu.cn/simple
4038

4139
```shell
4240
# 设置1张可用的GPU卡
43-
export CUDA_VISIBLE_DEVICES=0
41+
export CUDA_VISIBLE_DEVICES=0
4442
# windows下请执行以下命令
4543
# set CUDA_VISIBLE_DEVICES=0
4644

paddleseg/models/backbones/hrnet.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ def __init__(self,
360360
reduction_ratio=16,
361361
name=name + '_fc')
362362

363+
self.add = layers.add()
364+
self.relu = layers.Activation("relu")
365+
363366
def forward(self, x):
364367
residual = x
365368
conv1 = self.conv1(x)
@@ -372,8 +375,8 @@ def forward(self, x):
372375
if self.has_se:
373376
conv3 = self.se(conv3)
374377

375-
y = conv3 + residual
376-
y = F.relu(y)
378+
y = self.add(conv3, residual)
379+
y = self.relu(y)
377380
return y
378381

379382

@@ -419,6 +422,9 @@ def __init__(self,
419422
reduction_ratio=16,
420423
name=name + '_fc')
421424

425+
self.add = layers.add()
426+
self.relu = layers.Activation("relu")
427+
422428
def forward(self, x):
423429
residual = x
424430
conv1 = self.conv1(x)
@@ -430,8 +436,8 @@ def forward(self, x):
430436
if self.has_se:
431437
conv2 = self.se(conv2)
432438

433-
y = conv2 + residual
434-
y = F.relu(y)
439+
y = self.add(conv2, residual)
440+
y = self.relu(y)
435441
return y
436442

437443

0 commit comments

Comments
 (0)