未验证 提交 0db9a28e 编写于 作者: G Guanghua Yu 提交者: GitHub

update ACT quick start demo (#1116)

上级 bdffa0fa
# 自动压缩工具ACT(Auto Compression Tookit) # 自动压缩工具ACT(Auto Compression Tookit)
## 简介 ## 简介
PaddleSlim推出全新自动压缩工具(ACT),旨在通过Source-Free的方式,自动对预测模型进行压缩,压缩后模型可直接部署应用。ACT自动压缩工具主要特性如下: PaddleSlim推出全新自动化压缩工具(ACT),旨在通过Source-Free的方式,自动对预测模型进行压缩,压缩后模型可直接部署应用。ACT自动化压缩工具主要特性如下:
- **『更便捷』**:开发者无需了解或修改模型源码,直接使用导出的预测模型进行压缩; - **『更便捷』**:开发者无需了解或修改模型源码,直接使用导出的预测模型进行压缩;
- **『更智能』**:开发者简单配置即可启动压缩,ACT工具会自动优化得到最好预测模型; - **『更智能』**:开发者简单配置即可启动压缩,ACT工具会自动优化得到最好预测模型;
- **『更丰富』**:ACT中提供了量化训练、蒸馏、结构化剪枝、非结构化剪枝、多种离线量化方法及超参搜索等等,可任意搭配使用。 - **『更丰富』**:ACT中提供了量化训练、蒸馏、结构化剪枝、非结构化剪枝、多种离线量化方法及超参搜索等等,可任意搭配使用。
...@@ -14,32 +14,68 @@ PaddleSlim推出全新自动压缩工具(ACT),旨在通过Source-Free的 ...@@ -14,32 +14,68 @@ PaddleSlim推出全新自动压缩工具(ACT),旨在通过Source-Free的
## 快速上手 ## 快速上手
- 1.准备模型及数据集
```shell
# 下载MobileNet预测模型
wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/MobileNetV1_infer.tar
tar -xf MobileNetV1_infer.tar
# 下载ImageNet小型数据集
wget https://sys-p0.bj.bcebos.com/slim_ci/ILSVRC2012_data_demo.tar.gz
tar xf ILSVRC2012_data_demo.tar.gz
```
- 2.运行
```python ```python
# 导入依赖包 # 导入依赖包
from paddleslim.auto_compression.config_helpers import load_config import paddle
from PIL import Image
from paddle.vision.datasets import DatasetFolder
from paddle.vision.transforms import transforms
from paddleslim.auto_compression import AutoCompression from paddleslim.auto_compression import AutoCompression
from paddleslim.common.imagenet_reader import reader paddle.enable_static()
# 加载配置文件 # 定义DataSet
compress_config, train_config = load_slim_config("./image_classification/mobilenetv1_qat_dis.yaml") class ImageNetDataset(DatasetFolder):
def __init__(self, path, image_size=224):
super(ImageNetDataset, self).__init__(path)
normalize = transforms.Normalize(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.120, 57.375])
self.transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(image_size), transforms.Transpose(),
normalize
])
def __getitem__(self, idx):
img_path, _ = self.samples[idx]
return self.transform(Image.open(img_path).convert('RGB'))
def __len__(self):
return len(self.samples)
# 定义DataLoader # 定义DataLoader
train_loader = reader(mode='test') # DataLoader train_dataset = ImageNetDataset("./ILSVRC2012_data_demo/ILSVRC2012/train/")
image = paddle.static.data(
name='inputs', shape=[None] + [3, 224, 224], dtype='float32')
train_loader = paddle.io.DataLoader(train_dataset, feed_list=[image], batch_size=32)
# 开始自动压缩 # 开始自动压缩
ac = AutoCompression( ac = AutoCompression(
model_dir="./mobilenetv1_infer", model_dir="./MobileNetV1_infer/",
model_filename="model.pdmodel", model_filename="inference.pdmodel",
params_filename="model.pdiparams", params_filename="inference.pdiparams",
save_dir="output", save_dir="output",
strategy_config=compress_config, strategy_config=None,
train_config=train_config, train_config=None,
train_dataloader=train_loader, train_dataloader=train_loader,
eval_callback=None) # eval_function to verify accuracy eval_dataloader=train_loader) # eval_function to verify accuracy
ac.compress() ac.compress()
``` ```
**提示:** **提示:**
- DataLoader传入的数据集是待压缩模型所用的数据集,DataLoader继承自`paddle.io.DataLoader` - DataLoader传入的数据集是待压缩模型所用的数据集,DataLoader继承自`paddle.io.DataLoader`
- 如无需验证自动压缩过程中模型的精度,`eval_callback`可不传入function,程序会自动根据损失来选择最优模型。 - 如无需验证自动压缩过程中模型的精度,`eval_callback`可不传入function,程序会自动根据损失来选择最优模型。
- 自动压缩Config中定义量化、蒸馏、剪枝等压缩算法会合并执行,压缩策略有:量化+蒸馏,剪枝+蒸馏等等。 - 自动压缩Config中定义量化、蒸馏、剪枝等压缩算法会合并执行,压缩策略有:量化+蒸馏,剪枝+蒸馏等等。
## 应用示例 ## 应用示例
...@@ -52,11 +88,11 @@ ac.compress() ...@@ -52,11 +88,11 @@ ac.compress()
#### [NLP](./nlp) #### [NLP](./nlp)
#### 即将发布 #### 即将发布
- [ ] 更多自动压缩应用示例 - [ ] 更多自动压缩应用示例
- [ ] X2Paddle模型自动压缩示例 - [ ] X2Paddle模型自动压缩示例
## 其他 ## 其他
- ACT可以自动处理常见的预测模型,如果有更特殊的改造需求,可以参考[ACT超参配置教程](./hyperparameter_tutorial.md)来进行单独配置压缩策略。 - ACT可以自动处理常见的预测模型,如果有更特殊的改造需求,可以参考[ACT超参配置教程](./hyperparameter_tutorial.md)来进行单独配置压缩策略。
- 如果你发现任何关于ACT自动压缩工具的问题或者是建议, 欢迎通过[GitHub Issues](https://github.com/PaddlePaddle/PaddleSlim/issues)给我们提issues。同时欢迎贡献更多优秀模型,共建开源生态。 - 如果你发现任何关于ACT自动压缩工具的问题或者是建议, 欢迎通过[GitHub Issues](https://github.com/PaddlePaddle/PaddleSlim/issues)给我们提issues。同时欢迎贡献更多优秀模型,共建开源生态。
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
## 2. Benchmark ## 2. Benchmark
- MobileNetV1模型 - MobileNetV1模型
| 模型 | 策略 | Top-1 Acc | 耗时(ms) threads=4 | | 模型 | 策略 | Top-1 Acc | 耗时(ms) threads=4 |
|:------:|:------:|:------:|:------:| |:------:|:------:|:------:|:------:|
| MobileNetV1 | Base模型 | 70.90 | 39.041 | | MobileNetV1 | Base模型 | 70.90 | 39.041 |
| MobileNetV1 | 量化+蒸馏 | 70.49 | 29.238| | MobileNetV1 | 量化+蒸馏 | 70.49 | 29.238|
- 测试环境:`SDM710 2*A75(2.2GHz) 6*A55(1.7GHz)` - 测试环境:`SDM710 2*A75(2.2GHz) 6*A55(1.7GHz)`
...@@ -59,7 +59,7 @@ pip install paddleslim ...@@ -59,7 +59,7 @@ pip install paddleslim
```shell ```shell
wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/MobileNetV1_infer.tar wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/MobileNetV1_infer.tar
tar -zxvf MobileNetV1_infer.tar tar -xf MobileNetV1_infer.tar
``` ```
也可根据[PaddleClas文档](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/inference_deployment/export_model.md)导出Inference模型。 也可根据[PaddleClas文档](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/inference_deployment/export_model.md)导出Inference模型。
...@@ -73,20 +73,20 @@ python run.py \ ...@@ -73,20 +73,20 @@ python run.py \
--model_dir='MobileNetV1_infer' \ --model_dir='MobileNetV1_infer' \
--model_filename='inference.pdmodel' \ --model_filename='inference.pdmodel' \
--params_filename='inference.pdiparams' \ --params_filename='inference.pdiparams' \
--save_dir='./save_quant_mobilev1/' \ --save_dir='./output' \
--batch_size=128 \ --batch_size=128 \
--config_path='./configs/mobilev1.yaml'\ --config_path='./configs/mobilenetv1_qat_dis.yaml'\
--data_dir='ILSVRC2012' --data_dir='ILSVRC2012'
# 多卡启动 # 多卡启动
python -m paddle.distributed.launch run.py \ python -m paddle.distributed.launch run.py \
--model_dir='MobileNetV1_infer' \ --model_dir='MobileNetV1_infer' \
--model_filename='inference.pdmodel' \ --model_filename='inference.pdmodel' \
--params_filename='inference.pdiparams' \ --params_filename='inference.pdiparams' \
--save_dir='./save_quant_mobilev1/' \ --save_dir='./output' \
--batch_size=128 \ --batch_size=128 \
--config_path='./configs/mobilev1.yaml'\ --config_path='./configs/mobilenetv1_qat_dis.yaml'\
--data_dir='ILSVRC2012' --data_dir='ILSVRC2012'
``` ```
...@@ -96,4 +96,4 @@ python -m paddle.distributed.launch run.py \ ...@@ -96,4 +96,4 @@ python -m paddle.distributed.launch run.py \
- [Paddle Inference C++部署](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.5/docs/deployment/inference/cpp_inference.md) - [Paddle Inference C++部署](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.5/docs/deployment/inference/cpp_inference.md)
- [Paddle Lite部署](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.5/docs/deployment/lite/lite.md) - [Paddle Lite部署](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.5/docs/deployment/lite/lite.md)
## 5.FAQ ## 5.FAQ
\ No newline at end of file
...@@ -25,16 +25,16 @@ __all__ = [ ...@@ -25,16 +25,16 @@ __all__ = [
"prepare_strategy", "create_strategy_config", "get_final_quant_config" "prepare_strategy", "create_strategy_config", "get_final_quant_config"
] ]
### config tester to test the loss of quant_post # config tester to test the loss of quant_post
hpo_config_tester = { hpo_config_tester = {
"ptq_algo": ["avg", "mse", "KL"], "ptq_algo": ["avg"],
"weight_quantize_type": ['channel_wise_abs_max', 'abs_max'], "weight_quantize_type": ['channel_wise_abs_max', 'abs_max'],
"bias_correct": [False], "bias_correct": [False],
"batch_num": [2, 3], "batch_num": [5],
"max_quant_count": 1, "max_quant_count": 1,
} }
### default hpo config # default hpo config
default_hpo_config = { default_hpo_config = {
"ptq_algo": ["KL", "hist", "avg", "mse"], "ptq_algo": ["KL", "hist", "avg", "mse"],
"weight_quantize_type": ['channel_wise_abs_max', 'abs_max'], "weight_quantize_type": ['channel_wise_abs_max', 'abs_max'],
...@@ -44,11 +44,26 @@ default_hpo_config = { ...@@ -44,11 +44,26 @@ default_hpo_config = {
"max_quant_count": 20, "max_quant_count": 20,
} }
### default quant config, can be used by ptq&hpo and qat&distillation # default quant config, can be used by ptq&hpo and qat&distillation
default_quant_config = { default_quant_config = {
'quantize_op_types': ['conv2d', 'depthwise_conv2d', 'mul', 'matmul'], 'quantize_op_types': ['conv2d', 'depthwise_conv2d', 'mul', 'matmul'],
'weight_bits': 8, 'weight_bits': 8,
'activation_bits': 8 'activation_bits': 8,
"is_full_quantize": False,
"activation_quantize_type": 'range_abs_max',
"weight_quantize_type": 'abs_max',
"not_quant_pattern": ["skip_quant"],
}
# default train config
DefaultTrainConfig = {
"epochs": 1,
"eval_iter": 500,
"learning_rate": 0.0001,
"optimizer": "Momentum",
"optim_args": {
"weight_decay": 4.0e-05
},
} }
EXPERIENCE_STRATEGY_WITHOUT_LOSS = [ EXPERIENCE_STRATEGY_WITHOUT_LOSS = [
...@@ -118,6 +133,12 @@ def create_strategy_config(strategy_str, model_type): ...@@ -118,6 +133,12 @@ def create_strategy_config(strategy_str, model_type):
return configs return configs
def create_train_config(strategy_str, model_type):
# TDOD: support more strategy and model_type
train_config = TrainConfig(**DefaultTrainConfig)
return train_config
def prepare_strategy(model_dir, def prepare_strategy(model_dir,
model_filename, model_filename,
params_filename, params_filename,
...@@ -203,9 +224,9 @@ def prepare_strategy(model_dir, ...@@ -203,9 +224,9 @@ def prepare_strategy(model_dir,
return strategy_config return strategy_config
def get_final_quant_config(ptq_loss): def get_final_quant_config(ptq_loss, mode='DistilQuant'):
""" transform quantization tester config to real quantization config """ """ transform quantization tester config to real quantization config """
if ptq_loss <= MAGIC_EMD_DISTANCE: if mode == 'HPO':
quant_config = Quantization(**default_quant_config) quant_config = Quantization(**default_quant_config)
hpo_config = HyperParameterOptimization(**default_hpo_config) hpo_config = HyperParameterOptimization(**default_hpo_config)
configs = [{ configs = [{
...@@ -213,10 +234,11 @@ def get_final_quant_config(ptq_loss): ...@@ -213,10 +234,11 @@ def get_final_quant_config(ptq_loss):
'HyperParameterOptimization': hpo_config 'HyperParameterOptimization': hpo_config
}] }]
else: if mode == 'DistilQuant':
quant_config = Quantization(**default_quant_config) quant_config = Quantization(**default_quant_config)
dis_config = Distillation() dis_config = Distillation()
configs = [{'Quantization': quant_config, 'Distillation': dis_config}] configs = [{'Quantization': quant_config, 'Distillation': dis_config}]
_logger.info("Start Quantization and Distillation Training.")
return configs return configs
......
...@@ -24,14 +24,14 @@ import paddle ...@@ -24,14 +24,14 @@ import paddle
import paddle.distributed.fleet as fleet import paddle.distributed.fleet as fleet
if platform.system().lower() == 'linux': if platform.system().lower() == 'linux':
from ..quant import quant_post_hpo from ..quant import quant_post_hpo
from ..quant.quanter import convert from ..quant.quanter import convert, quant_post
from ..common.recover_program import recover_inference_program from ..common.recover_program import recover_inference_program
from ..common import get_logger from ..common import get_logger
from ..common.patterns import get_patterns from ..common.patterns import get_patterns
from ..analysis import TableLatencyPredictor from ..analysis import TableLatencyPredictor
from .create_compressed_program import build_distill_program, build_quant_program, build_prune_program, remove_unused_var_nodes from .create_compressed_program import build_distill_program, build_quant_program, build_prune_program, remove_unused_var_nodes
from .strategy_config import ProgramInfo, merge_config from .strategy_config import ProgramInfo, merge_config
from .auto_strategy import prepare_strategy, get_final_quant_config, create_strategy_config from .auto_strategy import prepare_strategy, get_final_quant_config, create_strategy_config, create_train_config
_logger = get_logger(__name__, level=logging.INFO) _logger = get_logger(__name__, level=logging.INFO)
...@@ -143,6 +143,11 @@ class AutoCompression: ...@@ -143,6 +143,11 @@ class AutoCompression:
self._strategy, self._config = self._prepare_strategy( self._strategy, self._config = self._prepare_strategy(
self.strategy_config) self.strategy_config)
# If train_config is None, set default train_config
if self.train_config is None:
self.train_config = create_train_config(self.strategy_config,
self.model_type)
def _prepare_envs(self): def _prepare_envs(self):
devices = paddle.device.get_device().split(':')[0] devices = paddle.device.get_device().split(':')[0]
places = paddle.device._convert_to_place(devices) places = paddle.device._convert_to_place(devices)
...@@ -248,8 +253,9 @@ class AutoCompression: ...@@ -248,8 +253,9 @@ class AutoCompression:
feed_target_names, fetch_targets) feed_target_names, fetch_targets)
config_dict = dict(config._asdict()) config_dict = dict(config._asdict())
if config_dict["prune_strategy"] == "gmp" and config_dict[ if "prune_strategy" in config_dict and config_dict[
'gmp_config'] is None: "prune_strategy"] == "gmp" and config_dict[
'gmp_config'] is None:
_logger.info( _logger.info(
"Calculating the iterations per epoch……(It will take some time)") "Calculating the iterations per epoch……(It will take some time)")
# NOTE:XXX: This way of calculating the iters needs to be improved. # NOTE:XXX: This way of calculating the iters needs to be improved.
...@@ -351,20 +357,57 @@ class AutoCompression: ...@@ -351,20 +357,57 @@ class AutoCompression:
).lower() == 'linux': ).lower() == 'linux':
ptq_loss = quant_post_hpo.g_min_emd_loss ptq_loss = quant_post_hpo.g_min_emd_loss
final_quant_config = get_final_quant_config(ptq_loss) final_quant_config = get_final_quant_config(
ptq_loss, mode='DistilQuant')
quant_strategy, quant_config = self._prepare_strategy( quant_strategy, quant_config = self._prepare_strategy(
final_quant_config) final_quant_config)
self.single_strategy_compress(quant_strategy[0], quant_config[0], self.single_strategy_compress(quant_strategy[0], quant_config[0],
strategy_idx) strategy_idx)
old_model_path = os.path.join( tmp_model_path = os.path.join(
self.save_dir, 'strategy_{}'.format(str(strategy_idx + 1))) self.save_dir, 'strategy_{}'.format(str(strategy_idx + 1)))
final_model_path = os.path.join(self.final_dir) final_model_path = os.path.join(self.final_dir)
shutil.move(old_model_path, final_model_path) if not os.path.exists(final_model_path):
os.makedirs(final_model_path)
tmp_model_file = os.path.join(tmp_model_path, 'model.pdmodel')
tmp_params_file = os.path.join(tmp_model_path, 'model.pdiparams')
final_model_file = os.path.join(final_model_path, 'model.pdmodel')
final_params_file = os.path.join(final_model_path, 'model.pdiparams')
shutil.move(tmp_model_file, final_model_file)
shutil.move(tmp_params_file, final_params_file)
_logger.info(
"==> Finished the ACT process and the final model is saved in:{}".
format(final_model_path))
os._exit(0) os._exit(0)
def single_strategy_compress(self, strategy, config, strategy_idx): def single_strategy_compress(self, strategy, config, strategy_idx):
### start compress, including train/eval model # start compress, including train/eval model
if strategy == 'ptq_hpo': # TODO: add the emd loss of evaluation model.
if strategy == 'quant_post':
quant_post(
self._exe,
model_dir=self.model_dir,
quantize_model_path=os.path.join(
self.save_dir, 'strategy_{}'.format(str(strategy_idx + 1))),
data_loader=self.train_dataloader,
model_filename=self.model_filename,
params_filename=self.params_filename,
save_model_filename=self.model_filename,
save_params_filename=self.params_filename,
batch_size=1,
batch_nums=config.batch_num,
algo=config.ptq_algo,
round_type='round',
bias_correct=config.bias_correct,
hist_percent=config.hist_percent,
quantizable_op_type=config.quantize_op_types,
is_full_quantize=config.is_full_quantize,
weight_bits=config.weight_bits,
activation_bits=config.activation_bits,
activation_quantize_type='range_abs_max',
weight_quantize_type=config.weight_quantize_type,
onnx_format=False)
elif strategy == 'ptq_hpo':
if platform.system().lower() != 'linux': if platform.system().lower() != 'linux':
raise NotImplementedError( raise NotImplementedError(
"post-quant-hpo is not support in system other than linux") "post-quant-hpo is not support in system other than linux")
...@@ -503,11 +546,12 @@ class AutoCompression: ...@@ -503,11 +546,12 @@ class AutoCompression:
test_program_info.program, test_program_info.program,
paddle.static.CompiledProgram) else test_program_info.program paddle.static.CompiledProgram) else test_program_info.program
paddle.static.load(test_program, if os.path.exists(os.path.join(self.save_dir, 'best_model.pdparams')):
os.path.join(self.save_dir, 'best_model')) paddle.static.load(test_program,
os.remove(os.path.join(self.save_dir, 'best_model.pdmodel')) os.path.join(self.save_dir, 'best_model'))
os.remove(os.path.join(self.save_dir, 'best_model.pdopt')) os.remove(os.path.join(self.save_dir, 'best_model.pdmodel'))
os.remove(os.path.join(self.save_dir, 'best_model.pdparams')) os.remove(os.path.join(self.save_dir, 'best_model.pdopt'))
os.remove(os.path.join(self.save_dir, 'best_model.pdparams'))
if 'qat' in strategy: if 'qat' in strategy:
float_program, int8_program = convert(test_program_info.program._program, self._places, self._quant_config, \ float_program, int8_program = convert(test_program_info.program._program, self._places, self._quant_config, \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册