Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
models
提交
217a6eb9
M
models
项目概览
PaddlePaddle
/
models
1 年多 前同步成功
通知
222
Star
6828
Fork
2962
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
602
列表
看板
标记
里程碑
合并请求
255
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
M
models
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
602
Issue
602
列表
看板
标记
里程碑
合并请求
255
合并请求
255
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
217a6eb9
编写于
10月 12, 2019
作者:
L
Liufang Sang
提交者:
whs
10月 12, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[PaddleSlim] add infer.py and add run cmd for yolov3 quantization demo (#3522)
上级
36a2e65b
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
322 addition
and
11 deletion
+322
-11
PaddleCV/PaddleDetection/slim/eval.py
PaddleCV/PaddleDetection/slim/eval.py
+0
-0
PaddleCV/PaddleDetection/slim/infer.py
PaddleCV/PaddleDetection/slim/infer.py
+276
-0
PaddleCV/PaddleDetection/slim/quantization/README.md
PaddleCV/PaddleDetection/slim/quantization/README.md
+41
-6
PaddleCV/PaddleDetection/slim/quantization/compress.py
PaddleCV/PaddleDetection/slim/quantization/compress.py
+1
-1
PaddleCV/PaddleDetection/slim/quantization/yolov3_mobilenet_v1_slim.yaml
...Detection/slim/quantization/yolov3_mobilenet_v1_slim.yaml
+2
-2
PaddleCV/PaddleDetection/slim/quantization/yolov3_mobilenet_v1_voc.yml
...leDetection/slim/quantization/yolov3_mobilenet_v1_voc.yml
+2
-2
未找到文件。
PaddleCV/PaddleDetection/slim/
quantization/
eval.py
→
PaddleCV/PaddleDetection/slim/eval.py
浏览文件 @
217a6eb9
文件已移动
PaddleCV/PaddleDetection/slim/infer.py
0 → 100644
浏览文件 @
217a6eb9
# 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.
from
__future__
import
absolute_import
from
__future__
import
division
from
__future__
import
print_function
import
os
import
sys
import
glob
import
numpy
as
np
from
PIL
import
Image
sys
.
path
.
append
(
"../../"
)
def
set_paddle_flags
(
**
kwargs
):
for
key
,
value
in
kwargs
.
items
():
if
os
.
environ
.
get
(
key
,
None
)
is
None
:
os
.
environ
[
key
]
=
str
(
value
)
# NOTE(paddle-dev): All of these flags should be set before
# `import paddle`. Otherwise, it would not take any effect.
set_paddle_flags
(
FLAGS_eager_delete_tensor_gb
=
0
,
# enable GC to save memory
)
from
paddle
import
fluid
from
ppdet.utils.cli
import
print_total_cfg
from
ppdet.core.workspace
import
load_config
,
merge_config
,
create
from
ppdet.modeling.model_input
import
create_feed
from
ppdet.data.data_feed
import
create_reader
from
ppdet.utils.eval_utils
import
parse_fetches
from
ppdet.utils.cli
import
ArgsParser
from
ppdet.utils.check
import
check_gpu
from
ppdet.utils.visualizer
import
visualize_results
import
ppdet.utils.checkpoint
as
checkpoint
import
logging
FORMAT
=
'%(asctime)s-%(levelname)s: %(message)s'
logging
.
basicConfig
(
level
=
logging
.
INFO
,
format
=
FORMAT
)
logger
=
logging
.
getLogger
(
__name__
)
def
get_save_image_name
(
output_dir
,
image_path
):
"""
Get save image name from source image path.
"""
if
not
os
.
path
.
exists
(
output_dir
):
os
.
makedirs
(
output_dir
)
image_name
=
os
.
path
.
split
(
image_path
)[
-
1
]
name
,
ext
=
os
.
path
.
splitext
(
image_name
)
return
os
.
path
.
join
(
output_dir
,
"{}"
.
format
(
name
))
+
ext
def
get_test_images
(
infer_dir
,
infer_img
):
"""
Get image path list in TEST mode
"""
assert
infer_img
is
not
None
or
infer_dir
is
not
None
,
\
"--infer_img or --infer_dir should be set"
assert
infer_img
is
None
or
os
.
path
.
isfile
(
infer_img
),
\
"{} is not a file"
.
format
(
infer_img
)
assert
infer_dir
is
None
or
os
.
path
.
isdir
(
infer_dir
),
\
"{} is not a directory"
.
format
(
infer_dir
)
images
=
[]
# infer_img has a higher priority
if
infer_img
and
os
.
path
.
isfile
(
infer_img
):
images
.
append
(
infer_img
)
return
images
infer_dir
=
os
.
path
.
abspath
(
infer_dir
)
assert
os
.
path
.
isdir
(
infer_dir
),
\
"infer_dir {} is not a directory"
.
format
(
infer_dir
)
exts
=
[
'jpg'
,
'jpeg'
,
'png'
,
'bmp'
]
exts
+=
[
ext
.
upper
()
for
ext
in
exts
]
for
ext
in
exts
:
images
.
extend
(
glob
.
glob
(
'{}/*.{}'
.
format
(
infer_dir
,
ext
)))
assert
len
(
images
)
>
0
,
"no image found in {}"
.
format
(
infer_dir
)
logger
.
info
(
"Found {} inference images in total."
.
format
(
len
(
images
)))
return
images
def
main
():
cfg
=
load_config
(
FLAGS
.
config
)
if
'architecture'
in
cfg
:
main_arch
=
cfg
.
architecture
else
:
raise
ValueError
(
"'architecture' not specified in config file."
)
merge_config
(
FLAGS
.
opt
)
# check if set use_gpu=True in paddlepaddle cpu version
check_gpu
(
cfg
.
use_gpu
)
# print_total_cfg(cfg)
if
'test_feed'
not
in
cfg
:
test_feed
=
create
(
main_arch
+
'TestFeed'
)
else
:
test_feed
=
create
(
cfg
.
test_feed
)
test_images
=
get_test_images
(
FLAGS
.
infer_dir
,
FLAGS
.
infer_img
)
test_feed
.
dataset
.
add_images
(
test_images
)
place
=
fluid
.
CUDAPlace
(
0
)
if
cfg
.
use_gpu
else
fluid
.
CPUPlace
()
exe
=
fluid
.
Executor
(
place
)
infer_prog
,
feed_var_names
,
fetch_list
=
fluid
.
io
.
load_inference_model
(
dirname
=
FLAGS
.
model_path
,
model_filename
=
FLAGS
.
model_name
,
params_filename
=
FLAGS
.
params_name
,
executor
=
exe
)
reader
=
create_reader
(
test_feed
)
feeder
=
fluid
.
DataFeeder
(
place
=
place
,
feed_list
=
feed_var_names
,
program
=
infer_prog
)
# parse infer fetches
assert
cfg
.
metric
in
[
'COCO'
,
'VOC'
],
\
"unknown metric type {}"
.
format
(
cfg
.
metric
)
extra_keys
=
[]
if
cfg
[
'metric'
]
==
'COCO'
:
extra_keys
=
[
'im_info'
,
'im_id'
,
'im_shape'
]
if
cfg
[
'metric'
]
==
'VOC'
:
extra_keys
=
[
'im_id'
,
'im_shape'
]
keys
,
values
,
_
=
parse_fetches
({
'bbox'
:
fetch_list
},
infer_prog
,
extra_keys
)
# parse dataset category
if
cfg
.
metric
==
'COCO'
:
from
ppdet.utils.coco_eval
import
bbox2out
,
mask2out
,
get_category_info
if
cfg
.
metric
==
"VOC"
:
from
ppdet.utils.voc_eval
import
bbox2out
,
get_category_info
anno_file
=
getattr
(
test_feed
.
dataset
,
'annotation'
,
None
)
with_background
=
getattr
(
test_feed
,
'with_background'
,
True
)
use_default_label
=
getattr
(
test_feed
,
'use_default_label'
,
False
)
clsid2catid
,
catid2name
=
get_category_info
(
anno_file
,
with_background
,
use_default_label
)
# whether output bbox is normalized in model output layer
is_bbox_normalized
=
False
# use tb-paddle to log image
if
FLAGS
.
use_tb
:
from
tb_paddle
import
SummaryWriter
tb_writer
=
SummaryWriter
(
FLAGS
.
tb_log_dir
)
tb_image_step
=
0
tb_image_frame
=
0
# each frame can display ten pictures at most.
imid2path
=
reader
.
imid2path
keys
=
[
'bbox'
]
for
iter_id
,
data
in
enumerate
(
reader
()):
feed_data
=
[[
d
[
0
],
d
[
1
]]
for
d
in
data
]
outs
=
exe
.
run
(
infer_prog
,
feed
=
feeder
.
feed
(
feed_data
),
fetch_list
=
fetch_list
,
return_numpy
=
False
)
res
=
{
k
:
(
np
.
array
(
v
),
v
.
recursive_sequence_lengths
())
for
k
,
v
in
zip
(
keys
,
outs
)
}
res
[
'im_id'
]
=
[[
d
[
2
]
for
d
in
data
]]
logger
.
info
(
'Infer iter {}'
.
format
(
iter_id
))
bbox_results
=
None
mask_results
=
None
if
'bbox'
in
res
:
bbox_results
=
bbox2out
([
res
],
clsid2catid
,
is_bbox_normalized
)
if
'mask'
in
res
:
mask_results
=
mask2out
([
res
],
clsid2catid
,
model
.
mask_head
.
resolution
)
# visualize result
im_ids
=
res
[
'im_id'
][
0
]
for
im_id
in
im_ids
:
image_path
=
imid2path
[
int
(
im_id
)]
image
=
Image
.
open
(
image_path
).
convert
(
'RGB'
)
# use tb-paddle to log original image
if
FLAGS
.
use_tb
:
original_image_np
=
np
.
array
(
image
)
tb_writer
.
add_image
(
"original/frame_{}"
.
format
(
tb_image_frame
),
original_image_np
,
tb_image_step
,
dataformats
=
'HWC'
)
image
=
visualize_results
(
image
,
int
(
im_id
),
catid2name
,
FLAGS
.
draw_threshold
,
bbox_results
,
mask_results
)
# use tb-paddle to log image with bbox
if
FLAGS
.
use_tb
:
infer_image_np
=
np
.
array
(
image
)
tb_writer
.
add_image
(
"bbox/frame_{}"
.
format
(
tb_image_frame
),
infer_image_np
,
tb_image_step
,
dataformats
=
'HWC'
)
tb_image_step
+=
1
if
tb_image_step
%
10
==
0
:
tb_image_step
=
0
tb_image_frame
+=
1
save_name
=
get_save_image_name
(
FLAGS
.
output_dir
,
image_path
)
logger
.
info
(
"Detection bbox results save in {}"
.
format
(
save_name
))
image
.
save
(
save_name
,
quality
=
95
)
if
__name__
==
'__main__'
:
parser
=
ArgsParser
()
parser
.
add_argument
(
"--infer_dir"
,
type
=
str
,
default
=
None
,
help
=
"Directory for images to perform inference on."
)
parser
.
add_argument
(
"--infer_img"
,
type
=
str
,
default
=
None
,
help
=
"Image path, has higher priority over --infer_dir"
)
parser
.
add_argument
(
"--output_dir"
,
type
=
str
,
default
=
"output"
,
help
=
"Directory for storing the output visualization files."
)
parser
.
add_argument
(
"--draw_threshold"
,
type
=
float
,
default
=
0.5
,
help
=
"Threshold to reserve the result for visualization."
)
parser
.
add_argument
(
"--use_tb"
,
type
=
bool
,
default
=
False
,
help
=
"whether to record the data to Tensorboard."
)
parser
.
add_argument
(
'--tb_log_dir'
,
type
=
str
,
default
=
"tb_log_dir/image"
,
help
=
'Tensorboard logging directory for image.'
)
parser
.
add_argument
(
'--model_path'
,
type
=
str
,
default
=
None
,
help
=
"inference model path"
)
parser
.
add_argument
(
'--model_name'
,
type
=
str
,
default
=
'__model__.infer'
,
help
=
"model filename for inference model"
)
parser
.
add_argument
(
'--params_name'
,
type
=
str
,
default
=
'__params__'
,
help
=
"params filename for inference model"
)
FLAGS
=
parser
.
parse_args
()
main
()
PaddleCV/PaddleDetection/slim/quantization/README.md
浏览文件 @
217a6eb9
...
...
@@ -44,9 +44,9 @@ step1: 开启显存优化策略
export FLAGS_fast_eager_deletion_mode=1
export FLAGS_eager_delete_tensor_gb=0.0
```
step2: 设置gpu卡
step2: 设置gpu卡
,目前的超参设置适合2卡训练
```
export CUDA_VISIBLE_DEVICES=0
export CUDA_VISIBLE_DEVICES=0
,1
```
step3: 开始训练
```
...
...
@@ -104,6 +104,12 @@ QuantizationFreezePass主要用于改变IrGraph中量化op和反量化op的顺
<img
src=
"./images/TransformForMobilePass.png"
height=
400
width=
400
hspace=
'10'
/>
<br
/>
<strong>
图4:应用TransformForMobilePass后的结果
</strong>
</p>
> 综上,可得在量化过程中有以下几种模型结构:
1.
原始模型
2.
经QuantizationTransformPass之后得到的适用于训练的量化模型结构,在${checkpoint_path}下保存的
`eval_model`
是这种结构,在训练过程中每个epoch结束时也使用这个网络结构进行评估,虽然这个模型结构不是最终想要的模型结构,但是每个epoch的评估结果可用来挑选模型。
3.
经QuantizationFreezePass之后得到的FP32模型结构,具体结构已在上面进行介绍。本文档中列出的数据集的评估结果是对FP32模型结构进行评估得到的结果。这种模型结构在训练过程中只会保存一次,也就是在量化配置文件中设置的
`end_epoch`
结束时进行保存,如果想将其他epoch的训练结果转化成FP32模型,可使用脚本
<a
href=
'./freeze.py'
>
PaddleSlim/classification/quantization/freeze.py
</a>
进行转化,具体使用方法在
[
评估
](
#评估
)
中介绍。
4.
经ConvertToInt8Pass之后得到的8-bit模型结构,具体结构已在上面进行介绍。这种模型结构在训练过程中只会保存一次,也就是在量化配置文件中设置的
`end_epoch`
结束时进行保存,如果想将其他epoch的训练结果转化成8-bit模型,可使用脚本
<a
href=
'./freeze.py'
>
slim/quantization/freeze.py
</a>
进行转化,具体使用方法在
[
评估
](
#评估
)
中介绍。
5.
经TransformForMobilePass之后得到的mobile模型结构,具体结构已在上面进行介绍。这种模型结构在训练过程中只会保存一次,也就是在量化配置文件中设置的
`end_epoch`
结束时进行保存,如果想将其他epoch的训练结果转化成mobile模型,可使用脚本
<a
href=
'./freeze.py'
>
slim/quantization/freeze.py
</a>
进行转化,具体使用方法在
[
评估
](
#评估
)
中介绍。
## 评估
...
...
@@ -115,10 +121,14 @@ QuantizationFreezePass主要用于改变IrGraph中量化op和反量化op的顺
如果不需要保存评估模型,可以在定义Compressor对象时,将
`save_eval_model`
选项设置为False(默认为True)。
脚本
<a
href=
".
/eval.py"
>
slim/quantization
/eval.py
</a>
中为使用该模型在评估数据集上做评估的示例。
脚本
<a
href=
".
./eval.py"
>
slim
/eval.py
</a>
中为使用该模型在评估数据集上做评估的示例。
运行命令为:
```
python eval.py --model_path ${checkpoint_path}/${epoch_id}/eval_model/ --model_name __model__ --params_name __params__ -c yolov3_mobilenet_v1_voc.yml
python ../eval.py \
--model_path ${checkpoint_path}/${epoch_id}/eval_model/ \
--model_name __model__ \
--params_name __params__ \
-c yolov3_mobilenet_v1_voc.yml
```
在评估之后,选取效果最好的epoch的模型,可使用脚本
<a
href=
'./freeze.py'
>
slim/quantization/freeze.py
</a>
将该模型转化为以上介绍的三种模型:FP32模型,int8模型,mobile模型,需要配置的参数为:
...
...
@@ -127,16 +137,41 @@ python eval.py --model_path ${checkpoint_path}/${epoch_id}/eval_model/ --model_n
-
weight_quant_type 模型参数的量化方式,和配置文件中的类型保持一致
-
save_path
`FP32`
,
`8-bit`
,
`mobile`
模型的保存路径,分别为
`${save_path}/float/`
,
`${save_path}/int8/`
,
`${save_path}/mobile/`
运行命令示例:
```
python freeze.py \
--model_path ${checkpoint_path}/${epoch_id}/eval_model/ \
--weight_quant_type ${weight_quant_type} \
--save_path ${any path you want}
```
### 最终评估模型
最终使用的评估模型是FP32模型,使用脚本
<a
href=
".
/eval.py"
>
slim/quantization
/eval.py
</a>
中为使用该模型在评估数据集上做评估的示例。
最终使用的评估模型是FP32模型,使用脚本
<a
href=
".
./eval.py"
>
slim
/eval.py
</a>
中为使用该模型在评估数据集上做评估的示例。
运行命令为:
```
python eval.py --model_path ${float_model_path} --model_name model --params_name weights -c yolov3_mobilenet_v1_voc.yml
python ../eval.py \
--model_path ${float_model_path}
--model_name model \
--params_name weights \
-c yolov3_mobilenet_v1_voc.yml
```
## 预测
### python预测
FP32模型可直接使用原生PaddlePaddle Fluid预测方法进行预测。
在脚本
<a
href=
"../infer.py"
>
slim/infer.py
</a>
中展示了如何使用fluid python API加载使用预测模型进行预测。
运行命令示例:
```
python ../infer.py \
--model_path ${save_path}/float \
--model_name model \
--params_name weights \
-c yolov3_mobilenet_v1_voc.yml \
--infer_dir ../../demo
```
### PaddleLite预测
...
...
PaddleCV/PaddleDetection/slim/quantization/compress.py
浏览文件 @
217a6eb9
...
...
@@ -201,6 +201,7 @@ def main():
checkpoint
.
load_params
(
exe
,
train_prog
,
cfg
.
pretrain_weights
)
best_box_ap_list
=
[]
def
eval_func
(
program
,
scope
):
...
...
@@ -208,7 +209,6 @@ def main():
#exe = fluid.Executor(place)
results
=
eval_run
(
exe
,
program
,
eval_reader
,
eval_keys
,
eval_values
,
eval_cls
,
test_data_feed
)
best_box_ap_list
=
[]
resolution
=
None
if
'mask'
in
results
[
0
]:
...
...
PaddleCV/PaddleDetection/slim/quantization/yolov3_mobilenet_v1_slim.yaml
浏览文件 @
217a6eb9
...
...
@@ -3,7 +3,7 @@ strategies:
quantization_strategy
:
class
:
'
QuantizationStrategy'
start_epoch
:
0
end_epoch
:
0
end_epoch
:
4
float_model_save_path
:
'
./output/yolov3/float'
mobile_model_save_path
:
'
./output/yolov3/mobile'
int8_model_save_path
:
'
./output/yolov3/int8'
...
...
@@ -14,7 +14,7 @@ strategies:
save_in_nodes
:
[
'
image'
,
'
im_size'
]
save_out_nodes
:
[
'
multiclass_nms_0.tmp_0'
]
compressor
:
epoch
:
1
epoch
:
5
checkpoint_path
:
'
./checkpoints/yolov3/'
strategies
:
-
quantization_strategy
PaddleCV/PaddleDetection/slim/quantization/yolov3_mobilenet_v1_voc.yml
浏览文件 @
217a6eb9
...
...
@@ -3,7 +3,7 @@ train_feed: YoloTrainFeed
eval_feed
:
YoloEvalFeed
test_feed
:
YoloTestFeed
use_gpu
:
true
max_iters
:
70
000
max_iters
:
1
000
log_smooth_window
:
20
save_dir
:
output
snapshot_iter
:
2000
...
...
@@ -45,8 +45,8 @@ LearningRate:
-
!PiecewiseDecay
gamma
:
0.1
milestones
:
-
1000
-
2000
-
8000
#- !LinearWarmup
#start_factor: 0.
#steps: 1000
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录