未验证 提交 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中提供了量化训练、蒸馏、结构化剪枝、非结构化剪枝、多种离线量化方法及超参搜索等等,可任意搭配使用。
......@@ -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
# 导入依赖包
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.common.imagenet_reader import reader
# 加载配置文件
compress_config, train_config = load_slim_config("./image_classification/mobilenetv1_qat_dis.yaml")
paddle.enable_static()
# 定义DataSet
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
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(
model_dir="./mobilenetv1_infer",
model_filename="model.pdmodel",
params_filename="model.pdiparams",
model_dir="./MobileNetV1_infer/",
model_filename="inference.pdmodel",
params_filename="inference.pdiparams",
save_dir="output",
strategy_config=compress_config,
train_config=train_config,
strategy_config=None,
train_config=None,
train_dataloader=train_loader,
eval_callback=None) # eval_function to verify accuracy
eval_dataloader=train_loader) # eval_function to verify accuracy
ac.compress()
```
**提示:**
- DataLoader传入的数据集是待压缩模型所用的数据集,DataLoader继承自`paddle.io.DataLoader`
- 如无需验证自动压缩过程中模型的精度,`eval_callback`可不传入function,程序会自动根据损失来选择最优模型。
- 自动压缩Config中定义量化、蒸馏、剪枝等压缩算法会合并执行,压缩策略有:量化+蒸馏,剪枝+蒸馏等等。
- 如无需验证自动压缩过程中模型的精度,`eval_callback`可不传入function,程序会自动根据损失来选择最优模型。
- 自动压缩Config中定义量化、蒸馏、剪枝等压缩算法会合并执行,压缩策略有:量化+蒸馏,剪枝+蒸馏等等。
## 应用示例
......@@ -52,11 +88,11 @@ ac.compress()
#### [NLP](./nlp)
#### 即将发布
- [ ] 更多自动压缩应用示例
- [ ] X2Paddle模型自动压缩示例
- [ ] 更多自动压缩应用示例
- [ ] X2Paddle模型自动压缩示例
## 其他
- 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 @@
## 2. Benchmark
- 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|
- 测试环境:`SDM710 2*A75(2.2GHz) 6*A55(1.7GHz)`
......@@ -59,7 +59,7 @@ pip install paddleslim
```shell
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模型。
......@@ -73,20 +73,20 @@ python run.py \
--model_dir='MobileNetV1_infer' \
--model_filename='inference.pdmodel' \
--params_filename='inference.pdiparams' \
--save_dir='./save_quant_mobilev1/' \
--save_dir='./output' \
--batch_size=128 \
--config_path='./configs/mobilev1.yaml'\
--config_path='./configs/mobilenetv1_qat_dis.yaml'\
--data_dir='ILSVRC2012'
# 多卡启动
python -m paddle.distributed.launch run.py \
--model_dir='MobileNetV1_infer' \
--model_filename='inference.pdmodel' \
--params_filename='inference.pdiparams' \
--save_dir='./save_quant_mobilev1/' \
--save_dir='./output' \
--batch_size=128 \
--config_path='./configs/mobilev1.yaml'\
--data_dir='ILSVRC2012'
--config_path='./configs/mobilenetv1_qat_dis.yaml'\
--data_dir='ILSVRC2012'
```
......@@ -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 Lite部署](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.5/docs/deployment/lite/lite.md)
## 5.FAQ
\ No newline at end of file
## 5.FAQ
......@@ -25,16 +25,16 @@ __all__ = [
"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 = {
"ptq_algo": ["avg", "mse", "KL"],
"ptq_algo": ["avg"],
"weight_quantize_type": ['channel_wise_abs_max', 'abs_max'],
"bias_correct": [False],
"batch_num": [2, 3],
"batch_num": [5],
"max_quant_count": 1,
}
### default hpo config
# default hpo config
default_hpo_config = {
"ptq_algo": ["KL", "hist", "avg", "mse"],
"weight_quantize_type": ['channel_wise_abs_max', 'abs_max'],
......@@ -44,11 +44,26 @@ default_hpo_config = {
"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 = {
'quantize_op_types': ['conv2d', 'depthwise_conv2d', 'mul', 'matmul'],
'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 = [
......@@ -118,6 +133,12 @@ def create_strategy_config(strategy_str, model_type):
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,
model_filename,
params_filename,
......@@ -203,9 +224,9 @@ def prepare_strategy(model_dir,
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 """
if ptq_loss <= MAGIC_EMD_DISTANCE:
if mode == 'HPO':
quant_config = Quantization(**default_quant_config)
hpo_config = HyperParameterOptimization(**default_hpo_config)
configs = [{
......@@ -213,10 +234,11 @@ def get_final_quant_config(ptq_loss):
'HyperParameterOptimization': hpo_config
}]
else:
if mode == 'DistilQuant':
quant_config = Quantization(**default_quant_config)
dis_config = Distillation()
configs = [{'Quantization': quant_config, 'Distillation': dis_config}]
_logger.info("Start Quantization and Distillation Training.")
return configs
......
......@@ -24,14 +24,14 @@ import paddle
import paddle.distributed.fleet as fleet
if platform.system().lower() == 'linux':
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 import get_logger
from ..common.patterns import get_patterns
from ..analysis import TableLatencyPredictor
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 .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)
......@@ -143,6 +143,11 @@ class AutoCompression:
self._strategy, self._config = self._prepare_strategy(
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):
devices = paddle.device.get_device().split(':')[0]
places = paddle.device._convert_to_place(devices)
......@@ -248,8 +253,9 @@ class AutoCompression:
feed_target_names, fetch_targets)
config_dict = dict(config._asdict())
if config_dict["prune_strategy"] == "gmp" and config_dict[
'gmp_config'] is None:
if "prune_strategy" in config_dict and config_dict[
"prune_strategy"] == "gmp" and config_dict[
'gmp_config'] is None:
_logger.info(
"Calculating the iterations per epoch……(It will take some time)")
# NOTE:XXX: This way of calculating the iters needs to be improved.
......@@ -351,20 +357,57 @@ class AutoCompression:
).lower() == 'linux':
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(
final_quant_config)
self.single_strategy_compress(quant_strategy[0], quant_config[0],
strategy_idx)
old_model_path = os.path.join(
tmp_model_path = os.path.join(
self.save_dir, 'strategy_{}'.format(str(strategy_idx + 1)))
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)
def single_strategy_compress(self, strategy, config, strategy_idx):
### start compress, including train/eval model
if strategy == 'ptq_hpo':
# start compress, including train/eval model
# 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':
raise NotImplementedError(
"post-quant-hpo is not support in system other than linux")
......@@ -503,11 +546,12 @@ class AutoCompression:
test_program_info.program,
paddle.static.CompiledProgram) else test_program_info.program
paddle.static.load(test_program,
os.path.join(self.save_dir, 'best_model'))
os.remove(os.path.join(self.save_dir, 'best_model.pdmodel'))
os.remove(os.path.join(self.save_dir, 'best_model.pdopt'))
os.remove(os.path.join(self.save_dir, 'best_model.pdparams'))
if os.path.exists(os.path.join(self.save_dir, 'best_model.pdparams')):
paddle.static.load(test_program,
os.path.join(self.save_dir, 'best_model'))
os.remove(os.path.join(self.save_dir, 'best_model.pdmodel'))
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:
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.
先完成此消息的编辑!
想要评论请 注册