提交 9a10a366 编写于 作者: L Liufang Sang 提交者: whs

fix icafe 3107 3104 3085 about quantization (#3889)

上级 532ebad1
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
## 概述 ## 概述
该示例使用PaddleSlim提供的[量化压缩策略](https://github.com/PaddlePaddle/models/blob/develop/PaddleSlim/docs/tutorial.md#1-quantization-aware-training%E9%87%8F%E5%8C%96%E4%BB%8B%E7%BB%8D)分类模型进行压缩。 该示例使用PaddleSlim提供的[量化压缩策略](https://github.com/PaddlePaddle/models/blob/develop/PaddleSlim/docs/tutorial.md#1-quantization-aware-training%E9%87%8F%E5%8C%96%E4%BB%8B%E7%BB%8D)检测模型进行压缩。
在阅读该示例前,建议您先了解以下内容: 在阅读该示例前,建议您先了解以下内容:
- [检测模型的常规训练方法](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/PaddleDetection) - [检测模型的常规训练方法](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/PaddleDetection)
...@@ -41,10 +41,11 @@ ...@@ -41,10 +41,11 @@
step1: 设置gpu卡 step1: 设置gpu卡
``` ```
export CUDA_VISIBLE_DEVICES=0 export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
``` ```
step2: 开始训练 step2: 开始训练
使用PaddleDetection提供的配置文件在用8卡进行训练:
使用PaddleDetection提供的配置文件用8卡进行训练:
``` ```
python compress.py \ python compress.py \
......
...@@ -49,7 +49,7 @@ from ppdet.data.data_feed import create_reader ...@@ -49,7 +49,7 @@ from ppdet.data.data_feed import create_reader
from ppdet.utils.eval_utils import parse_fetches, eval_results from ppdet.utils.eval_utils import parse_fetches, eval_results
from ppdet.utils.stats import TrainingStats from ppdet.utils.stats import TrainingStats
from ppdet.utils.cli import ArgsParser, print_total_cfg from ppdet.utils.cli import ArgsParser, print_total_cfg
from ppdet.utils.check import check_gpu, check_version from ppdet.utils.check import check_gpu
import ppdet.utils.checkpoint as checkpoint import ppdet.utils.checkpoint as checkpoint
from ppdet.modeling.model_input import create_feed from ppdet.modeling.model_input import create_feed
...@@ -121,8 +121,7 @@ def main(): ...@@ -121,8 +121,7 @@ def main():
# check if set use_gpu=True in paddlepaddle cpu version # check if set use_gpu=True in paddlepaddle cpu version
check_gpu(cfg.use_gpu) check_gpu(cfg.use_gpu)
# print_total_cfg(cfg)
#check_version()
if cfg.use_gpu: if cfg.use_gpu:
devices_num = fluid.core.get_cuda_device_count() devices_num = fluid.core.get_cuda_device_count()
else: else:
......
...@@ -195,19 +195,6 @@ def main(): ...@@ -195,19 +195,6 @@ def main():
model_filename='model', model_filename='model',
params_filename='weights') params_filename='weights')
logger.info("convert the freezed pass to paddle-lite execution")
mobile_pass = TransformForMobilePass()
mobile_pass.apply(test_graph)
mobile_program = test_graph.to_program()
fluid.io.save_inference_model(
dirname=os.path.join(FLAGS.save_path, 'mobile'),
feeded_var_names=feed_names,
target_vars=fetch_targets,
executor=exe,
main_program=mobile_program,
model_filename='model',
params_filename='weights')
if __name__ == '__main__': if __name__ == '__main__':
parser = ArgsParser() parser = ArgsParser()
......
...@@ -5,7 +5,6 @@ strategies: ...@@ -5,7 +5,6 @@ strategies:
start_epoch: 0 start_epoch: 0
end_epoch: 4 end_epoch: 4
float_model_save_path: './output/yolov3/float' float_model_save_path: './output/yolov3/float'
mobile_model_save_path: './output/yolov3/mobile'
int8_model_save_path: './output/yolov3/int8' int8_model_save_path: './output/yolov3/int8'
weight_bits: 8 weight_bits: 8
activation_bits: 8 activation_bits: 8
......
...@@ -33,20 +33,23 @@ add_arg('model_name', str, "__model__", "model filename for inference model") ...@@ -33,20 +33,23 @@ add_arg('model_name', str, "__model__", "model filename for inference model")
add_arg('params_name', str, "__params__", "params filename for inference model") add_arg('params_name', str, "__params__", "params filename for inference model")
# yapf: enable # yapf: enable
def eval(args): def eval(args):
# parameters from arguments # parameters from arguments
place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place) exe = fluid.Executor(place)
val_program, feed_target_names, fetch_targets = fluid.io.load_inference_model(args.model_path, val_program, feed_target_names, fetch_targets = fluid.io.load_inference_model(
exe, args.model_path,
model_filename=args.model_name, exe,
params_filename=args.params_name) model_filename=args.model_name,
params_filename=args.params_name)
val_reader = paddle.batch(reader.val(), batch_size=128) val_reader = paddle.batch(reader.val(), batch_size=128)
feeder = fluid.DataFeeder(place=place, feed_list=feed_target_names, program=val_program) feeder = fluid.DataFeeder(
place=place, feed_list=feed_target_names, program=val_program)
results=[] results = []
for batch_id, data in enumerate(val_reader()): for batch_id, data in enumerate(val_reader()):
# top1_acc, top5_acc # top1_acc, top5_acc
...@@ -56,8 +59,8 @@ def eval(args): ...@@ -56,8 +59,8 @@ def eval(args):
label = [[d[1]] for d in data] label = [[d[1]] for d in data]
feed_data = feeder.feed(image) feed_data = feeder.feed(image)
pred = exe.run(val_program, pred = exe.run(val_program,
feed=feed_data, feed=feed_data,
fetch_list=fetch_targets) fetch_list=fetch_targets)
pred = np.array(pred[0]) pred = np.array(pred[0])
label = np.array(label) label = np.array(label)
sort_array = pred.argsort(axis=1) sort_array = pred.argsort(axis=1)
...@@ -68,23 +71,25 @@ def eval(args): ...@@ -68,23 +71,25 @@ def eval(args):
for i in range(len(label)): for i in range(len(label)):
if label[i][0] in top_5_pred[i]: if label[i][0] in top_5_pred[i]:
acc_num += 1 acc_num += 1
top_5 = acc_num / len(label) top_5 = float(acc_num) / len(label)
results.append([top_1, top_5]) results.append([top_1, top_5])
else: else:
# eval "eval model", which inputs are image and label, output is top1 and top5 accuracy # eval "eval model", which inputs are image and label, output is top1 and top5 accuracy
result = exe.run(val_program, result = exe.run(val_program,
feed=feeder.feed(data), feed=feeder.feed(data),
fetch_list=fetch_targets) fetch_list=fetch_targets)
result = [np.mean(r) for r in result] result = [np.mean(r) for r in result]
results.append(result) results.append(result)
result = np.mean(np.array(results), axis=0) result = np.mean(np.array(results), axis=0)
print("top1_acc/top5_acc= {}".format(result)) print("top1_acc/top5_acc= {}".format(result))
sys.stdout.flush() sys.stdout.flush()
def main(): def main():
args = parser.parse_args() args = parser.parse_args()
print_arguments(args) print_arguments(args)
eval(args) eval(args)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
>运行该示例前请安装Paddle1.6或更高版本 >运行该示例前请安装Paddle1.6或更高版本。 本示例中的run.sh脚本仅适用于linux系统,在windows环境下,请参考run.sh内容编写适合windows环境的脚本。
# 分类模型量化压缩示例 # 分类模型量化压缩示例
...@@ -40,7 +40,7 @@ cost = fluid.layers.cross_entropy(input=out, label=label) ...@@ -40,7 +40,7 @@ cost = fluid.layers.cross_entropy(input=out, label=label)
- use_gpu: 是否使用gpu。如果选择使用GPU,请确保当前环境和Paddle版本支持GPU。默认为True。 - use_gpu: 是否使用gpu。如果选择使用GPU,请确保当前环境和Paddle版本支持GPU。默认为True。
- batch_size: 在量化之后,对模型进行fine-tune训练时用的batch size。 - batch_size: 在量化之后,对模型进行fine-tune训练时用的batch size。
- model: 要压缩的目标模型,该示例支持'MobileNet', 'MobileNetV2'和'ResNet50'。 - model: 要压缩的目标模型,该示例支持'MobileNet', 'MobileNetV2'和'ResNet34'。
- pretrained_model: 预训练模型的路径,可以从[这里](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification#%E5%B7%B2%E5%8F%91%E5%B8%83%E6%A8%A1%E5%9E%8B%E5%8F%8A%E5%85%B6%E6%80%A7%E8%83%BD)下载。 - pretrained_model: 预训练模型的路径,可以从[这里](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification#%E5%B7%B2%E5%8F%91%E5%B8%83%E6%A8%A1%E5%9E%8B%E5%8F%8A%E5%85%B6%E6%80%A7%E8%83%BD)下载。
- config_file: 压缩策略的配置文件。 - config_file: 压缩策略的配置文件。
...@@ -49,7 +49,7 @@ cost = fluid.layers.cross_entropy(input=out, label=label) ...@@ -49,7 +49,7 @@ cost = fluid.layers.cross_entropy(input=out, label=label)
### 训练时的模型结构 ### 训练时的模型结构
这部分介绍来源于[量化low-level API介绍](https://github.com/PaddlePaddle/models/tree/develop/PaddleSlim/quant_low_level_api#1-%E9%87%8F%E5%8C%96%E8%AE%AD%E7%BB%83low-level-apis%E4%BB%8B%E7%BB%8D) 这部分介绍来源于[量化low-level API介绍](https://github.com/PaddlePaddle/models/tree/develop/PaddleSlim/quant_low_level_api#1-%E9%87%8F%E5%8C%96%E8%AE%AD%E7%BB%83low-level-apis%E4%BB%8B%E7%BB%8D)
PaddlePaddle框架中有四个和量化相关的IrPass, 分别是QuantizationTransformPass、QuantizationFreezePass、ConvertToInt8Pass以及TransformForMobilePass。在训练时,对网络应用了QuantizationTransformPass,作用是在网络中的conv2d、depthwise_conv2d、mul等算子的各个输入前插入连续的量化op和反量化op,并改变相应反向算子的某些输入。示例图如下: PaddlePaddle框架中和量化相关的IrPass有QuantizationTransformPass、QuantizationFreezePass、ConvertToInt8Pass。在训练时,对网络应用了QuantizationTransformPass,作用是在网络中的conv2d、depthwise_conv2d、mul等算子的各个输入前插入连续的量化op和反量化op,并改变相应反向算子的某些输入。示例图如下:
<p align="center"> <p align="center">
<img src="../../docs/images/usage/TransformPass.png" height=400 width=520 hspace='10'/> <br /> <img src="../../docs/images/usage/TransformPass.png" height=400 width=520 hspace='10'/> <br />
...@@ -65,10 +65,10 @@ PaddlePaddle框架中有四个和量化相关的IrPass, 分别是QuantizationTra ...@@ -65,10 +65,10 @@ PaddlePaddle框架中有四个和量化相关的IrPass, 分别是QuantizationTra
>注意:配置文件中的信息不会保存在断点中,重启前对配置文件的修改将会生效。 >注意:配置文件中的信息不会保存在断点中,重启前对配置文件的修改将会生效。
### 保存评估和预测模型 ### 保存评估和预测模型
如果在配置文件的量化策略中设置了`float_model_save_path`, `int8_model_save_path`, `mobile_model_save_path`, 在训练结束后,会保存模型量化压缩之后用于评估和预测的模型。接下来介绍这三种模型的区别。 如果在配置文件的量化策略中设置了`float_model_save_path`, `int8_model_save_path`,在训练结束后,会保存模型量化压缩之后用于评估和预测的模型。接下来介绍这2种模型的区别。
#### FP32模型 #### FP32模型
在介绍量化训练时的模型结构时介绍了PaddlePaddle框架中有四个和量化相关的IrPass, 分别是QuantizationTransformPass、QuantizationFreezePass、ConvertToInt8Pass以及TransformForMobilePass。FP32预测模型是在应用QuantizationFreezePass并删除eval_program中多余的operators之后,保存的模型。 在介绍量化训练时的模型结构时介绍了PaddlePaddle框架中和量化相关的IrPass, 有QuantizationTransformPass、QuantizationFreezePass、ConvertToInt8Pass。FP32预测模型是在应用QuantizationFreezePass并删除eval_program中多余的operators之后,保存的模型。
QuantizationFreezePass主要用于改变IrGraph中量化op和反量化op的顺序,即将类似图1中的量化op和反量化op顺序改变为图2中的布局。除此之外,QuantizationFreezePass还会将`conv2d``depthwise_conv2d``mul`等算子的权重离线量化为int8_t范围内的值(但数据类型仍为float32),以减少预测过程中对权重的量化操作,示例如图2: QuantizationFreezePass主要用于改变IrGraph中量化op和反量化op的顺序,即将类似图1中的量化op和反量化op顺序改变为图2中的布局。除此之外,QuantizationFreezePass还会将`conv2d``depthwise_conv2d``mul`等算子的权重离线量化为int8_t范围内的值(但数据类型仍为float32),以减少预测过程中对权重的量化操作,示例如图2:
...@@ -86,20 +86,13 @@ QuantizationFreezePass主要用于改变IrGraph中量化op和反量化op的顺 ...@@ -86,20 +86,13 @@ QuantizationFreezePass主要用于改变IrGraph中量化op和反量化op的顺
<strong>图3:应用ConvertToInt8Pass后的结果</strong> <strong>图3:应用ConvertToInt8Pass后的结果</strong>
</p> </p>
#### mobile模型
经TransformForMobilePass转换后,用户可得到兼容[paddle-lite](https://github.com/PaddlePaddle/Paddle-Lite)移动端预测库的量化模型。paddle-mobile中的量化op和反量化op的名称分别为`quantize``dequantize``quantize`算子和PaddlePaddle框架中的`fake_quantize_abs_max`算子簇的功能类似,`dequantize` 算子和PaddlePaddle框架中的`fake_dequantize_max_abs`算子簇的功能相同。若选择paddle-mobile执行量化训练输出的模型,则需要将`fake_quantize_abs_max`等算子改为`quantize`算子以及将`fake_dequantize_max_abs`等算子改为`dequantize`算子,示例如图4:
<p align="center">
<img src="../../docs/images/usage/TransformForMobilePass.png" height=400 width=400 hspace='10'/> <br />
<strong>图4:应用TransformForMobilePass后的结果</strong>
</p>
> 综上,可得在量化过程中有以下几种模型结构: > 综上,可得在量化过程中有以下几种模型结构:
1. 原始模型 1. 原始模型
2. 经QuantizationTransformPass之后得到的适用于训练的量化模型结构,在${checkpoint_path}下保存的`eval_model`是这种结构,在训练过程中每个epoch结束时也使用这个网络结构进行评估,虽然这个模型结构不是最终想要的模型结构,但是每个epoch的评估结果可用来挑选模型。 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>进行转化,具体使用方法在[评估](#评估)中介绍。 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'>PaddleSlim/classification/quantization/freeze.py</a>进行转化,具体使用方法在[评估](#评估)中介绍。 4. 经ConvertToInt8Pass之后得到的8-bit模型结构,具体结构已在上面进行介绍。这种模型结构在训练过程中只会保存一次,也就是在量化配置文件中设置的`end_epoch`结束时进行保存,如果想将其他epoch的训练结果转化成8-bit模型,可使用脚本 <a href='./freeze.py'>PaddleSlim/classification/quantization/freeze.py</a>进行转化,具体使用方法在[评估](#评估)中介绍。
5. 经TransformForMobilePass之后得到的mobile模型结构,具体结构已在上面进行介绍。这种模型结构在训练过程中只会保存一次,也就是在量化配置文件中设置的`end_epoch`结束时进行保存,如果想将其他epoch的训练结果转化成mobile模型,可使用脚本 <a href='./freeze.py'>PaddleSlim/classification/quantization/freeze.py</a>进行转化,具体使用方法在[评估](#评估)中介绍。
## 评估 ## 评估
...@@ -120,11 +113,11 @@ python eval.py \ ...@@ -120,11 +113,11 @@ python eval.py \
--model_path ${checkpoint_path}/${epoch_id}/eval_model --model_path ${checkpoint_path}/${epoch_id}/eval_model
``` ```
在评估之后,选取效果最好的epoch的模型,可使用脚本 <a href='./freeze.py'>PaddleSlim/classification/quantization/freeze.py</a>将该模型转化为以上介绍的三种模型:FP32模型,8-bit模型,mobile模型,需要配置的参数为: 在评估之后,选取效果最好的epoch的模型,可使用脚本 <a href='./freeze.py'>PaddleSlim/classification/quantization/freeze.py</a>将该模型转化为以上介绍的2种模型:FP32模型,8-bit模型,需要配置的参数为:
- model_path, 加载的模型路径,`为${checkpoint_path}/${epoch_id}/eval_model/` - model_path, 加载的模型路径,`为${checkpoint_path}/${epoch_id}/eval_model/`
- weight_quant_type 模型参数的量化方式,和配置文件中的类型保持一致 - weight_quant_type 模型参数的量化方式,和配置文件中的类型保持一致
- save_path `FP32`, `8-bit`, `mobile`模型的保存路径,分别为 `${save_path}/float/`, `${save_path}/int8/`, `${save_path}/mobile/` - save_path `FP32`, `8-bit`模型的保存路径,分别为 `${save_path}/float/`, `${save_path}/int8/`
运行命令示例: 运行命令示例:
``` ```
...@@ -166,11 +159,43 @@ python infer.py \ ...@@ -166,11 +159,43 @@ python infer.py \
### PaddleLite预测 ### PaddleLite预测
FP32模型可使用Paddle-Lite进行加载预测,可参见教程[Paddle-Lite如何加载运行量化模型](https://github.com/PaddlePaddle/Paddle-Lite/wiki/model_quantization) FP32模型可使用Paddle-Lite进行加载预测,可参见教程[Paddle-Lite如何加载运行量化模型](https://github.com/PaddlePaddle/Paddle-Lite/wiki/model_quantization)
mobile预测模型兼容Paddle-Lite(Paddle-Mobile的升级版), 使用方法可参考[Paddle-Lite文档](https://paddlepaddle.github.io/Paddle-Lite/). ## 如何进行部分量化
通过在定义op时指定 ``name_scope````skip_quant``可对这个op跳过量化。比如在<a href="../models/resnet.py">PaddleSlim/classification/models/resnet.py</a>中,将某个conv的定义作如下改变:
原定义:
```
conv = self.conv_bn_layer(
input=input,
num_filters=64,
filter_size=7,
stride=2,
act='relu',
name=prefix_name + conv1_name)
```
跳过量化时的定义:
```
with fluid.name_scope('skip_quant'):
conv = self.conv_bn_layer(
input=input,
num_filters=64,
filter_size=7,
stride=2,
act='relu',
name=prefix_name + conv1_name)
```
在脚本 <a href="./compress.py">PaddleSlim/classification/quantization/compress.py</a> 中,统计了``conv`` op的数量和以``fake_quantize``开头的量化op的数量,在对一些``conv`` op跳过之后,可发现以``fake_quantize``开头的量化op的数量变少。
## 示例结果 ## 示例结果
>当前release的结果并非超参调优后的最好结果,仅做示例参考,后续我们会优化当前结果。
### MobileNetV1 ### MobileNetV1
| weight量化方式 | activation量化方式| top1_acc/top5_acc |Paddle Fluid inference time(ms)| Paddle Lite inference time(ms)| 模型下载| | weight量化方式 | activation量化方式| top1_acc/top5_acc |Paddle Fluid inference time(ms)| Paddle Lite inference time(ms)| 模型下载|
...@@ -203,14 +228,23 @@ fluid.optimizer.Momentum(momentum=0.9, ...@@ -203,14 +228,23 @@ fluid.optimizer.Momentum(momentum=0.9,
>训练超参: >训练超参:
### ResNet50 优化器
```
fluid.optimizer.Momentum(momentum=0.9,
learning_rate=fluid.layers.piecewise_decay(
boundaries=[5000 * 12],
values=[0.0001, 0.00001]),
regularization=fluid.regularizer.L2Decay(1e-4))
```
8卡,batch size 1024,epoch 30, 挑选好的结果
### ResNet34
| weight量化方式 | activation量化方式| top1_acc/top5_acc |Paddle Fluid inference time(ms)| Paddle Lite inference time(ms)|模型下载| | weight量化方式 | activation量化方式| top1_acc/top5_acc |Paddle Fluid inference time(ms)| Paddle Lite inference time(ms)|模型下载|
|---|---|---|---|---|---| |---|---|---|---|---|---|
|baseline|- |76.50%/93.00%|- |-|[下载模型](http://paddle-imagenet-models-name.bj.bcebos.com/ResNet50_pretrained.tar)| |baseline|- |74.57%/92.14%|- |-|-|
|abs_max|abs_max|76.71%/93.10% |- |-|[下载模型](https://paddle-slim-models.bj.bcebos.com/quantization%2Fresnet50_w_abs_a_abs_7670_9310.tar.gz)| |abs_max|abs_max||- |-|-|
|abs_max|moving_average_abs_max|76.65%/93.12% |- |-|[下载模型](https://paddle-slim-models.bj.bcebos.com/quantization%2Fresnet50_w_abs_a_move_7665_9312.tar.gz) | |abs_max|moving_average_abs_max||- |-|-|
|channel_wise_abs_max|abs_max|76.56%/93.05% |- |-| [下载模型](https://paddle-slim-models.bj.bcebos.com/quantization%2Fresnet50_w_chan_a_abs_7656_9304.tar.gz)| |channel_wise_abs_max|abs_max||- |-| -|
>训练超参: >训练超参:
......
...@@ -38,8 +38,9 @@ def compress(args): ...@@ -38,8 +38,9 @@ def compress(args):
image_shape = "3,224,224" image_shape = "3,224,224"
image_shape = [int(m) for m in image_shape.split(",")] image_shape = [int(m) for m in image_shape.split(",")]
image = fluid.layers.data(name='image', shape=image_shape, dtype='float32') image = fluid.data(
label = fluid.layers.data(name='label', shape=[1], dtype='int64') name='image', shape=[None] + image_shape, dtype='float32')
label = fluid.data(name='label', shape=[None, 1], dtype='int64')
# model definition # model definition
model = models.__dict__[args.model]() model = models.__dict__[args.model]()
...@@ -95,10 +96,21 @@ def compress(args): ...@@ -95,10 +96,21 @@ def compress(args):
eval_fetch_list=val_fetch_list, eval_fetch_list=val_fetch_list,
teacher_programs=[], teacher_programs=[],
train_optimizer=opt, train_optimizer=opt,
prune_infer_model=[[image.name], [out.name]],
distiller_optimizer=None) distiller_optimizer=None)
com_pass.config(args.config_file) com_pass.config(args.config_file)
com_pass.run() com_pass.run()
conv_op_num = 0
fake_quant_op_num = 0
for op in com_pass.context.eval_graph.ops():
if op._op.type == 'conv2d':
conv_op_num += 1
elif op._op.type.startswith('fake_quantize'):
fake_quant_op_num += 1
print('conv op num {}'.format(conv_op_num))
print('fake quant op num {}'.format(fake_quant_op_num))
def main(): def main():
args = parser.parse_args() args = parser.parse_args()
......
...@@ -5,7 +5,6 @@ strategies: ...@@ -5,7 +5,6 @@ strategies:
start_epoch: 0 start_epoch: 0
end_epoch: 29 end_epoch: 29
float_model_save_path: './output/mobilenet_v1/float' float_model_save_path: './output/mobilenet_v1/float'
mobile_model_save_path: './output/mobilenet_v1/mobile'
int8_model_save_path: './output/mobilenet_v1/int8' int8_model_save_path: './output/mobilenet_v1/int8'
weight_bits: 8 weight_bits: 8
activation_bits: 8 activation_bits: 8
......
...@@ -5,7 +5,6 @@ strategies: ...@@ -5,7 +5,6 @@ strategies:
start_epoch: 0 start_epoch: 0
end_epoch: 29 end_epoch: 29
float_model_save_path: './output/mobilenet_v2/float' float_model_save_path: './output/mobilenet_v2/float'
mobile_model_save_path: './output/mobilenet_v2/mobile'
int8_model_save_path: './output/mobilenet_v2/int8' int8_model_save_path: './output/mobilenet_v2/int8'
weight_bits: 8 weight_bits: 8
activation_bits: 8 activation_bits: 8
......
...@@ -3,9 +3,8 @@ strategies: ...@@ -3,9 +3,8 @@ strategies:
quantization_strategy: quantization_strategy:
class: 'QuantizationStrategy' class: 'QuantizationStrategy'
start_epoch: 0 start_epoch: 0
end_epoch: 29 end_epoch: 0
float_model_save_path: './output/resnet34/float' float_model_save_path: './output/resnet34/float'
mobile_model_save_path: './output/resnet34/mobile'
int8_model_save_path: './output/resnet34/int8' int8_model_save_path: './output/resnet34/int8'
weight_bits: 8 weight_bits: 8
activation_bits: 8 activation_bits: 8
...@@ -14,7 +13,7 @@ strategies: ...@@ -14,7 +13,7 @@ strategies:
save_in_nodes: ['image'] save_in_nodes: ['image']
save_out_nodes: ['fc_0.tmp_2'] save_out_nodes: ['fc_0.tmp_2']
compressor: compressor:
epoch: 30 epoch: 1
checkpoint_path: './checkpoints/resnet34/' checkpoint_path: './checkpoints/resnet34/'
strategies: strategies:
- quantization_strategy - quantization_strategy
...@@ -45,81 +45,83 @@ add_arg('save_path', str, './output', 'Path to save inference model') ...@@ -45,81 +45,83 @@ add_arg('save_path', str, './output', 'Path to save inference model')
add_arg('weight_quant_type', str, 'abs_max', 'quantization type for weight') add_arg('weight_quant_type', str, 'abs_max', 'quantization type for weight')
# yapf: enable # yapf: enable
def eval(args): def eval(args):
# parameters from arguments # parameters from arguments
place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place) exe = fluid.Executor(place)
val_program, feed_names, fetch_targets = fluid.io.load_inference_model(args.model_path, val_program, feed_names, fetch_targets = fluid.io.load_inference_model(
exe, args.model_path,
model_filename="__model__", exe,
params_filename="__params__") model_filename="__model__.infer",
params_filename="__params__")
val_reader = paddle.batch(reader.val(), batch_size=128) val_reader = paddle.batch(reader.val(), batch_size=128)
feeder = fluid.DataFeeder(place=place, feed_list=feed_names, program=val_program) feeder = fluid.DataFeeder(
place=place, feed_list=feed_names, program=val_program)
results=[] results = []
for batch_id, data in enumerate(val_reader()): for batch_id, data in enumerate(val_reader()):
image = [[d[0]] for d in data]
label = [[d[1]] for d in data]
feed_data = feeder.feed(image)
pred = exe.run(val_program, feed=feed_data, fetch_list=fetch_targets)
pred = np.array(pred[0])
label = np.array(label)
sort_array = pred.argsort(axis=1)
top_1_pred = sort_array[:, -1:][:, ::-1]
top_1 = np.mean(label == top_1_pred)
top_5_pred = sort_array[:, -5:][:, ::-1]
acc_num = 0
for i in range(len(label)):
if label[i][0] in top_5_pred[i]:
acc_num += 1
top_5 = acc_num / len(label)
results.append([top_1, top_5])
# top1_acc, top5_acc
result = exe.run(val_program,
feed=feeder.feed(data),
fetch_list=fetch_targets)
result = [np.mean(r) for r in result]
results.append(result)
result = np.mean(np.array(results), axis=0) result = np.mean(np.array(results), axis=0)
print("top1_acc/top5_acc= {}".format(result)) print("top1_acc/top5_acc= {}".format(result))
sys.stdout.flush() sys.stdout.flush()
_logger.info("freeze the graph for inference") _logger.info("freeze the graph for inference")
test_graph = IrGraph(core.Graph(val_program.desc), for_test=True) test_graph = IrGraph(core.Graph(val_program.desc), for_test=True)
freeze_pass = QuantizationFreezePass( freeze_pass = QuantizationFreezePass(
scope=fluid.global_scope(), scope=fluid.global_scope(),
place=place, place=place,
weight_quantize_type=args.weight_quant_type) weight_quantize_type=args.weight_quant_type)
freeze_pass.apply(test_graph) freeze_pass.apply(test_graph)
server_program = test_graph.to_program() server_program = test_graph.to_program()
fluid.io.save_inference_model( fluid.io.save_inference_model(
dirname=os.path.join(args.save_path, 'float'), dirname=os.path.join(args.save_path, 'float'),
feeded_var_names=feed_names, feeded_var_names=feed_names,
target_vars=fetch_targets, target_vars=fetch_targets,
executor=exe, executor=exe,
main_program=server_program, main_program=server_program,
model_filename='model', model_filename='model',
params_filename='weights') params_filename='weights')
_logger.info("convert the weights into int8 type") _logger.info("convert the weights into int8 type")
convert_int8_pass = ConvertToInt8Pass( convert_int8_pass = ConvertToInt8Pass(
scope=fluid.global_scope(), scope=fluid.global_scope(), place=place)
place=place)
convert_int8_pass.apply(test_graph) convert_int8_pass.apply(test_graph)
server_int8_program = test_graph.to_program() server_int8_program = test_graph.to_program()
fluid.io.save_inference_model( fluid.io.save_inference_model(
dirname=os.path.join(args.save_path, 'int8'), dirname=os.path.join(args.save_path, 'int8'),
feeded_var_names=feed_names, feeded_var_names=feed_names,
target_vars=fetch_targets, target_vars=fetch_targets,
executor=exe, executor=exe,
main_program=server_int8_program, main_program=server_int8_program,
model_filename='model', model_filename='model',
params_filename='weights') params_filename='weights')
_logger.info("convert the freezed pass to paddle-lite execution")
mobile_pass = TransformForMobilePass()
mobile_pass.apply(test_graph)
mobile_program = test_graph.to_program()
fluid.io.save_inference_model(
dirname=os.path.join(args.save_path, 'mobile'),
feeded_var_names=feed_names,
target_vars=fetch_targets,
executor=exe,
main_program=mobile_program,
model_filename='model',
params_filename='weights')
def main(): def main():
args = parser.parse_args() args = parser.parse_args()
print_arguments(args) print_arguments(args)
eval(args) eval(args)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册