diff --git a/PaddleSlim/README.md b/PaddleSlim/README.md index b12b3c3e488b066048b08abac0606a7bc5bf73a3..561e7ef1016a558f4aa1b20bb310645098ed31a4 100644 --- a/PaddleSlim/README.md +++ b/PaddleSlim/README.md @@ -23,7 +23,7 @@ --- # PaddleSlim模型压缩工具库 -PaddleSlim是PaddlePaddle框架的一个子模块。PaddleSlim首次在PaddlePaddle 1.4版本中发布。在PaddleSlim中,实现了目前主流的网络剪枝、量化、蒸馏三种压缩策略,主要用于压缩图像领域模型。在后续版本中,会添加更多的压缩策略,以及完善对NLP领域模型的支持。 +PaddleSlim是PaddlePaddle框架的一个子模块,主要用于压缩图像领域模型。在PaddleSlim中,不仅实现了目前主流的网络剪枝、量化、蒸馏三种压缩策略,还实现了超参数搜索和小模型网络结构搜索功能。在后续版本中,会添加更多的压缩策略,以及完善对NLP领域模型的支持。 ## 目录 - [特色](#特色) @@ -45,7 +45,7 @@ Paddle-Slim工具库有以下特点: ### 效果好 -- 对于冗余信息较少的MobileNetV1模型,卷积核剪切策略依然可缩减模型大小,并保持尽量少的精度损失。 +- 对于冗余信息较少的MobileNetV1模型,模型通道剪裁策略依然可缩减模型大小,并保持尽量少的精度损失。 - 蒸馏压缩策略可明显提升原始模型的精度。 - 量化训练与蒸馏的组合使用,可同时做到缩减模型大小和提升模型精度。 @@ -53,8 +53,8 @@ Paddle-Slim工具库有以下特点: ### 功能更强更灵活 -- 剪切压缩过程自动化 -- 剪切压缩策略支持更多网络结构 +- 模型剪裁压缩过程自动化 +- 模型剪裁压缩策略支持更多网络结构 - 蒸馏支持多种方式,用户可自定义组合loss - 支持快速配置多种压缩策略组合使用 @@ -63,10 +63,10 @@ Paddle-Slim工具库有以下特点: ## 架构介绍 这里简要介绍模型压缩工具实现的整体原理,便于理解使用流程。 -**图 1**为模型压缩工具的架构图,从上到下为API依赖关系。蒸馏模块、量化模块和剪切模块都间接依赖底层的paddle框架。目前,模型压缩工具作为了PaddlePaddle框架的一部分,所以已经安装普通版本paddle的用户需要重新下载安装支持模型压缩功能的paddle,才能使用压缩功能。 +**图 1**为模型压缩工具的架构图,从上到下为API依赖关系。蒸馏模块、量化模块和剪裁模块都间接依赖底层的paddle框架。目前,模型压缩工具作为了PaddlePaddle框架的一部分,所以已经安装普通版本paddle的用户需要重新下载安装支持模型压缩功能的paddle,才能使用压缩功能。

-
+
图 1

@@ -82,11 +82,11 @@ Paddle-Slim工具库有以下特点: ## 功能列表 -### 剪切 +### 模型剪裁 -- 支持敏感度和uniform两种方式 +- 支持通道均匀模型剪裁(uniform pruning)、基于敏感度的模型剪裁、基于进化算法的自动模型剪裁三种方式 - 支持VGG、ResNet、MobileNet等各种类型的网络 -- 支持用户自定义剪切范围 +- 支持用户自定义剪裁范围 ### 量化训练 @@ -103,11 +103,15 @@ Paddle-Slim工具库有以下特点: - 支持L2 loss - 支持softmax with cross-entropy loss +### 轻量神经网络结构自动搜索(Light-NAS) + +- 支持基于进化算法的轻量神经网络结构自动搜索(Light-NAS) + ### 其它功能 - 支持配置文件管理压缩任务超参数 - 支持多种压缩策略组合使用 -- 蒸馏和剪切压缩过程支持checkpoints功能 +- 蒸馏和模型剪裁压缩过程支持checkpoints功能 ## 简要实验结果 @@ -131,14 +135,14 @@ Paddle-Slim工具库有以下特点: 注:abs_max为动态量化,moving_average_abs_max为静态量化, channel_wise_abs_max是对卷积权重进行分channel量化。 -### 卷积核剪切 +### 模型通道剪裁 数据:ImageNet 1000类 模型:MobileNetV1 原始模型大小:17M 原始精度(top5/top1): 89.54% / 70.91% -#### Uniform剪切 +#### 模型通道均匀剪裁 | FLOPS |model size| 精度损失(top5/top1)|精度(top5/top1) | |---|---|---|---| @@ -146,7 +150,7 @@ Paddle-Slim工具库有以下特点: | -60%|-55.9%(7.5M)|-1.34% / -2.67%|88.22% / 68.24%| | -70%|-65.3%(5.9M)|-2.55% / -4.34%|86.99% / 66.57%| -#### 基于敏感度迭代剪切 +#### 基于敏感度迭代剪裁 | FLOPS |精度(top5/top1)| |---|---| @@ -175,12 +179,22 @@ Paddle-Slim工具库有以下特点: | Baseline|89.54% / 70.91%|17.0M| | ResNet50蒸馏|90.92% / 71.97%|17.0M| | ResNet50蒸馏训练 + 量化|90.94% / 72.01%|4.8M| -| 剪切-50% FLOPS|89.13% / 69.83%|9.0M| -| 剪切-50% FLOPS + 量化|89.11% / 69.20%|2.3M| +| 剪裁-50% FLOPS|89.13% / 69.83%|9.0M| +| 剪裁-50% FLOPS + 量化|89.11% / 69.20%|2.3M| + +### 模型结构搜索实验 + +数据:ImageNet 1000类 + +| |Light-NAS-model0 |Light-NAS-model1 |MobileNetV2 | +|---|---|---|---| +|FLOPS|-3%|-17%|-0%| +|top1/top5 accuracy|72.45%/90.70%|71.84%/90.45%|71.90%/90.55% | +|GPU cost|1.2K GPU hours|1.2K GPU hours|-| ## 模型导出格式 -压缩框架支持导出以下格式的模型: +模型压缩框架支持以下格式模型导出: - **Paddle Fluid模型格式:** Paddle Fluid模型格式,可通过Paddle框架加载使用。 - **Paddle Mobile模型格式:** 仅在量化训练策略时使用,兼容[Paddle Mobile](https://github.com/PaddlePaddle/paddle-mobile)的模型格式。 diff --git a/PaddleSlim/docs/demo.md b/PaddleSlim/docs/demo.md index 8090fb736f3c15fdfb229d607cd488e0a554ecee..f09a7997f1492c0af260e3d863334258fd860313 100644 --- a/PaddleSlim/docs/demo.md +++ b/PaddleSlim/docs/demo.md @@ -25,18 +25,20 @@ - [压缩脚本准备](#2-压缩脚本介绍) - [蒸馏示例](#31-蒸馏) - [剪切示例](#32-uniform剪切) -- [量化示例](#34-int8量化训练) -- [蒸馏后量化示例](#35-蒸馏后int8量化) -- [剪切后量化示例](#36-剪切后int8量化) +- [量化示例](#35-int8量化训练) +- [蒸馏后量化示例](#36-蒸馏后int8量化) +- [剪切后量化示例](#37-剪切后int8量化) +- [小模型结构搜索示例](#38-小模型结构搜索示例) ## 0. 概述 该示例参考[PaddlePaddle/models/fluid/PaddleCV/image_classification](https://github.com/PaddlePaddle/models/tree/develop/fluid/PaddleCV/image_classification)下代码,分别实现了以下策略: 1. 蒸馏:用ResNet50对MobileNetV1的在ImageNet 1000数据上的蒸馏训练。 2. 剪切:对预训练好的MobileNetV1进行剪切 -3. 量化:对预训练好的MobileNetV1进行int8量化训练 -4. 蒸馏量化组合:先用ResNet50对MobileNetV1进行蒸馏,再对蒸馏后得到的模型进行int8量化训练。 -5. 剪切量化组合:先用Uniform剪切策略对MobileNetV1进行剪切,再对剪切后的模型进行int8量化训练 +3. 量化:对预训练好的MobileNetV1进行int8量化训练 +4. 蒸馏量化组合:先用ResNet50对MobileNetV1进行蒸馏,再对蒸馏后得到的模型进行int8量化训练。 +5. 剪切量化组合:先用Uniform剪切策略对MobileNetV1进行剪切,再对剪切后的模型进行int8量化训练 +5. 小模型结构搜索示例: 先用模拟退火策略搜索出一组tokens, 再用该tokens构建网络进行训练。 本示例完整代码链接:https://github.com/PaddlePaddle/models/tree/develop/PaddleSlim @@ -212,7 +214,64 @@ python compress.py \ 图3

-### 3.4 int8量化训练 +### 3.4 剪切率超参搜索 + +在该示例中,使用模拟退火策略搜索出一组最优的剪切率,将MobileNetV1模型剪掉50%的FLOPS. +修改run.sh, 执行以下命令,搜索一组剪切率: + +``` + +# for auto filter pruning +#--------------------------- +export CUDA_VISIBLE_DEVICES=0 +python compress.py \ +--model "MobileNet" \ +--pretrained_model ./pretrain/MobileNetV1_pretrained \ +--compress_config ./configs/auto_prune.yaml + +``` + +通过上述步骤,得到一组最优的tokens, 将其按以下方式设置到`auto_prune.yaml`文件中: + +``` +strategies: + auto_pruning_strategy: + class: 'AutoPruneStrategy' + pruner: 'pruner_1' + controller: 'sa_controller' + start_epoch: 0 + end_epoch: 200 + retrain_epoch: 200 + max_ratio: 0.50 + min_ratio: 0.48 + uniform_range: 0.4 + init_tokens: [39, 38, 38, 24, 21, 34, 24, 29, 19, 11, 33, 36, 39] + pruned_params: '.*_sep_weights' + metric_name: 'acc_top1' +compressor: + epoch: 200 + checkpoint_path: './checkpoints_auto_pruning/' + strategies: + - auto_pruning_strategy +``` + +其中,需要修改的选项有: + +- end_epoch: 将其修改为200,训练任务共执行200个epochs +- retrain_epoch: 将其修改为200,当前任务的200个epochs全为训练,不做搜索。 +- init_tokens: 在auto_pruning_strategy下新增init_tokens, 为上一步骤中搜索出的最优tokens. +- compressor::epoch: 修改为200,整个压缩任务执行200个epochs后退出。 + + +该示例在评估数据集上的准确率结果如下: + +| FLOPS |模型大小| 精度(top5/top1) |pruned ratios| +|---|---|---|---| +| -50%|- |88.86% / 69.64%|[0.39, 0.38, 0.38, 0.24, 0.21, 0.34, 0.24, 0.29, 0.19, 0.11, 0.33, 0.36, 0.39]| + +>该搜索策略有一定的随机性,用上述搜索参数,不一定能搜索完全一样的结果。 + +### 3.5 int8量化训练 修改run.sh, 执行以下命令,执行int8量化训练示例: @@ -234,7 +293,7 @@ python compress.py \ |MobileNetV1|-71.76%(4.8M)|89.64% / 71.01%| -### 3.5 蒸馏后int8量化 +### 3.6 蒸馏后int8量化 本示例先用ResNet50模型对MobileNetV1蒸馏训练120个epochs,然后再对MobileNetV1模型进行动态int8量化训练。 修改run.sh, 执行以下命令,执行蒸馏与int8量化训练结合的模型压缩示例: @@ -256,7 +315,7 @@ python compress.py \ | --- | --- | --- | | MobileNet v1 | -71.76%(4.8M)| 72.01% | -### 3.6 剪切后int8量化 +### 3.7 剪切后int8量化 本示例先将预训练好的MobileNetV1模型剪掉50% FLOPS, 让后再对其进行动态int8量化训练。 修改run.sh, 执行以下命令,执行剪切与int8量化训练结合的模型压缩示例: @@ -276,3 +335,36 @@ python compress.py \ | 模型(剪切FLOPS+动态int8量化) | 模型大小 | 精度(top1) | | --- | --- | --- | | MobileNet v1(剪切FLOPS -50%) | -86.47%(2.3M) | 69.20% | + +### 3.7 小模型结构搜索示例 + +本示例先用模拟退火策略搜索出一组tokens, 再用搜索出的tokens初始化构建模型进行训练。 + +step1: 进入路径`PaddlePaddle/models/PaddleSlim/light_nas/`。 + +step2: 在当前路径下,新建软链接指向上级目录的data: `ln -s ../data data`。 + +step3: 修改`compress.xml`文件, 将参数server_ip设置为当前机器的ip。 + +step4: 执行`sh run.sh`, 可根据实际情况修改`run.sh`中的`CUDA_VISIBLE_DEVICES`。 + +step5: 修改`light_nas_space.py`文件中的`LightNASSpace::init_tokens`, 使其返回step4中搜到的最优tokens。 + +step6: 修改compress.xml文件,将compressor下的`strategies`去掉。 + +step7: 执行`sh run.sh`进行训练任务。 + +该示例两组结果如下: + +| - | Light-NAS-model0| Light-NAS-model1 | MobileNetV2 | +|---|---|---|---| +| FLOPS|-3% | -17% | -0% | +| top1 accuracy| 72.45%| 71.84%| 71.90% | +|GPU cost|1.2K GPU hours(V100)|1.2K GPU hours(V100)|-| +|tokens|tokens1|tokens2|| + + +| token name | tokens| +|---|---| +|tokens1|[3, 1, 1, 0, 1, 0, 3, 2, 1, 0, 1, 0, 3, 1, 1, 0, 1, 0, 2, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0]| +|tokens2|[3, 1, 1, 0, 1, 0, 3, 2, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 2, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1]| diff --git a/PaddleSlim/docs/images/framework_0.png b/PaddleSlim/docs/images/framework_0.png index 82d6f8bf1d0439e29d12d7a2bf81f109dbe95b71..223f384f23775403129a69967bbe9e891dfa77ff 100644 Binary files a/PaddleSlim/docs/images/framework_0.png and b/PaddleSlim/docs/images/framework_0.png differ diff --git a/PaddleSlim/docs/images/light-nas-block.png b/PaddleSlim/docs/images/light-nas-block.png new file mode 100644 index 0000000000000000000000000000000000000000..c469c1b634cef2dcf4c6e4f6c7907e7d7e9aaf09 Binary files /dev/null and b/PaddleSlim/docs/images/light-nas-block.png differ diff --git a/PaddleSlim/docs/tutorial.md b/PaddleSlim/docs/tutorial.md index e4dd13d29d16916dcbf6d637edf510d30693e68d..3f2ec6e536337d1fec24a08c2479397575180106 100644 --- a/PaddleSlim/docs/tutorial.md +++ b/PaddleSlim/docs/tutorial.md @@ -20,8 +20,9 @@ ## 目录 - [量化原理介绍](#1-quantization-aware-training量化介绍) -- [剪切原理介绍](#2-卷积核剪切原理) +- [剪裁原理介绍](#2-卷积核剪裁原理) - [蒸馏原理介绍](#3-蒸馏) +- [轻量级模型结构搜索原理介绍](#4-轻量级模型结构搜索) ## 1. Quantization Aware Training量化介绍 @@ -119,16 +120,16 @@ $$ Vt = (1 - k) * V + k * V_{t-1} $$ -## 2. 卷积核剪切原理 +## 2. 卷积核剪裁原理 该策略参考paper: [Pruning Filters for Efficient ConvNets](https://arxiv.org/pdf/1608.08710.pdf) 该策略通过减少卷积层中卷积核的数量,来减小模型大小和降低模型计算复杂度。 -### 2.1 剪切卷积核 +### 2.1 剪裁卷积核 -**剪切注意事项1** -剪切一个conv layer的filter,需要修改后续conv layer的filter. 如**图4**所示,剪掉Xi的一个filter,会导致$X_{i+1}$少一个channel, $X_{i+1}$对应的filter在input_channel纬度上也要减1. +**剪裁注意事项1** +剪裁一个conv layer的filter,需要修改后续conv layer的filter. 如**图4**所示,剪掉Xi的一个filter,会导致$X_{i+1}$少一个channel, $X_{i+1}$对应的filter在input_channel纬度上也要减1.

@@ -137,9 +138,9 @@ $$ Vt = (1 - k) * V + k * V_{t-1} $$

-**剪切注意事项2** +**剪裁注意事项2** -如**图5**所示,剪切完$X_i$之后,根据注意事项1我们从$X_{i+1}$的filter中删除了一行(图中蓝色行),在计算$X_{i+1}$的filters的l1_norm(图中绿色一列)的时候,有两种选择: +如**图5**所示,剪裁完$X_i$之后,根据注意事项1我们从$X_{i+1}$的filter中删除了一行(图中蓝色行),在计算$X_{i+1}$的filters的l1_norm(图中绿色一列)的时候,有两种选择: 算上被删除的一行:independent pruning 减去被删除的一行:greedy pruning @@ -148,9 +149,9 @@ $$ Vt = (1 - k) * V + k * V_{t-1} $$ 图5

-**剪切注意事项3** -在对ResNet等复杂网络剪切的时候,还要考虑到后当前卷积层的修改对上一层卷积层的影响。 -如**图6**所示,在对residual block剪切时,$X_{i+1}$层如何剪切取决于project shortcut的剪切结果,因为我们要保证project shortcut的output和$X_{i+1}$的output能被正确的concat. +**剪裁注意事项3** +在对ResNet等复杂网络剪裁的时候,还要考虑到后当前卷积层的修改对上一层卷积层的影响。 +如**图6**所示,在对residual block剪裁时,$X_{i+1}$层如何剪裁取决于project shortcut的剪裁结果,因为我们要保证project shortcut的output和$X_{i+1}$的output能被正确的concat.

@@ -158,25 +159,25 @@ $$ Vt = (1 - k) * V + k * V_{t-1} $$ 图6

-### 2.2 Uniform剪切卷积网络 +### 2.2 Uniform剪裁卷积网络 -每层剪切一样比例的卷积核。 -在剪切一个卷积核之前,按l1_norm对filter从高到低排序,越靠后的filter越不重要,优先剪掉靠后的filter. +每层剪裁一样比例的卷积核。 +在剪裁一个卷积核之前,按l1_norm对filter从高到低排序,越靠后的filter越不重要,优先剪掉靠后的filter. -### 2.3 基于敏感度剪切卷积网络 +### 2.3 基于敏感度剪裁卷积网络 根据每个卷积层敏感度的不同,剪掉不同比例的卷积核。 #### 两个假设 - 在一个conv layer的parameter内部,按l1_norm对filter从高到低排序,越靠后的filter越不重要。 -- 两个layer剪切相同的比例的filters,我们称对模型精度影响更大的layer的敏感度相对高。 +- 两个layer剪裁相同的比例的filters,我们称对模型精度影响更大的layer的敏感度相对高。 -#### 剪切filter的指导原则 +#### 剪裁filter的指导原则 -- layer的剪切比例与其敏感度成反比 -- 优先剪切layer内l1_norm相对低的filter +- layer的剪裁比例与其敏感度成反比 +- 优先剪裁layer内l1_norm相对低的filter #### 敏感度的理解 @@ -185,21 +186,21 @@ $$ Vt = (1 - k) * V + k * V_{t-1} $$ 图7

-如**图7**所示,横坐标是将filter剪切掉的比例,竖坐标是精度的损失,每条彩色虚线表示的是网络中的一个卷积层。 -以不同的剪切比例**单独**剪切一个卷积层,并观察其在验证数据集上的精度损失,并绘出**图7**中的虚线。虚线上升较慢的,对应的卷积层相对不敏感,我们优先剪不敏感的卷积层的filter. +如**图7**所示,横坐标是将filter剪裁掉的比例,竖坐标是精度的损失,每条彩色虚线表示的是网络中的一个卷积层。 +以不同的剪裁比例**单独**剪裁一个卷积层,并观察其在验证数据集上的精度损失,并绘出**图7**中的虚线。虚线上升较慢的,对应的卷积层相对不敏感,我们优先剪不敏感的卷积层的filter. -#### 选择最优的剪切率组合 +#### 选择最优的剪裁率组合 -我们将**图7**中的折线拟合为**图8**中的曲线,每在竖坐标轴上选取一个精度损失值,就在横坐标轴上对应着一组剪切率,如**图8**中黑色实线所示。 -用户给定一个模型整体的剪切率,我们通过移动**图5**中的黑色实线来找到一组满足条件的且合法的剪切率。 +我们将**图7**中的折线拟合为**图8**中的曲线,每在竖坐标轴上选取一个精度损失值,就在横坐标轴上对应着一组剪裁率,如**图8**中黑色实线所示。 +用户给定一个模型整体的剪裁率,我们通过移动**图5**中的黑色实线来找到一组满足条件的且合法的剪裁率。


图8

-#### 迭代剪切 -考虑到多个卷积层间的相关性,一个卷积层的修改可能会影响其它卷积层的敏感度,我们采取了多次剪切的策略,步骤如下: +#### 迭代剪裁 +考虑到多个卷积层间的相关性,一个卷积层的修改可能会影响其它卷积层的敏感度,我们采取了多次剪裁的策略,步骤如下: - step1: 统计各卷积层的敏感度信息 - step2: 根据当前统计的敏感度信息,对每个卷积层剪掉少量filter, 并统计FLOPS,如果FLOPS已满足要求,进入step4,否则进行step3。 @@ -222,9 +223,53 @@ Fast Optimization, Network Minimization and Transfer Learning](http://openaccess 由于小模型和大模型之间通过L2 loss进行监督,必须保证两个FSP矩阵的维度必须相同,而FSP矩阵的维度为M*N,其中M、N分别为输入和输出特征的channel数,因此大模型和小模型的FSP矩阵需要一一对应。 +## 4. 轻量级模型结构搜索 +深度学习模型在很多任务上都取得了不错的效果,网络结构的好坏对最终模型的效果有非常重要的影响。手工设计网络需要非常丰富的经验和众多尝试,并且众多的超参数和网络结构参数会产生爆炸性的组合,常规的random search几乎不可行,因此最近几年自动模型搜索技术(Neural Architecture Search)成为研究热点。区别于传统NAS,我们专注在搜索精度高并且速度快的模型结构,我们将该功能统称为Light-NAS. -## 4. 参考文献 +### 4.1 搜索策略 + +搜索策略定义了使用怎样的算法可以快速、准确找到最优的网络结构参数配置。常见的搜索方法包括:强化学习、贝叶斯优化、进化算法、基于梯度的算法。我们当前的实现以模拟退火算法为主。 + +#### 4.1.1 模拟退火 + +模拟退火算法来源于固体退火原理,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。 + +鉴于物理中固体物质的退火过程与一般组合优化问题之间的相似性,我们将其用于网络结构的搜索。 + +使用模拟退火算法搜索模型的过程如下: + +$$ +T_k = T_0*\theta^k +$$ + +\begin{equation} +P(r_k) = +\begin{cases} +e^{\frac{(r_k-r)}{T_k}} & r_k < r\\ +1 & r_k>=r +\end{cases} +\end{equation} + +在第k次迭代,搜到的网络为$N_k$, 对$N_k$训练若干epoch后,在测试集上得到reward为$r_k$, 以概率$P(r_k)$接受$r_k$,即执行$r=r_k$。$r$在搜索过程起始时被初始化为0. $T_0$为初始化温度,$\theta$为温度衰减系数,$T_k$为第k次迭代的温度。 + + +在我们的NAS任务中,区别于RL每次重新生成一个完整的网络,我们将网络结构映射成一段编码,第一次随机初始化,然后每次随机修改编码中的一部分(对应于网络结构的一部分)生成一个新的编码,然后将这个编码再映射回网络结构,通过在训练集上训练一定的epochs后的精度以及网络延时融合获得reward,来指导退火算法的收敛。 + + +### 4.2 搜索空间 + +搜索空间定义了优化问题的变量,变量规模决定了搜索算法的难度和搜索时间。因此为了加快搜索速度,定义一个合理的搜索空间至关重要。在Light-NAS中,为了加速搜索速度,我们将一个网络划分为多个block,先手动按链状层级结构堆叠c,再 使用搜索算法自动搜索每个block内部的结构。 + +因为要搜索出在移动端运行速度快的模型,我们参考了MobileNetV2中的Linear Bottlenecks和Inverted residuals结构,搜索每一个Inverted residuals中的具体参数,包括kernelsize、channel扩张倍数、重复次数、channels number。如图10所示: + +

+
+图10 +

+ + +## 5. 参考文献 1. [High-Performance Hardware for Machine Learning](https://media.nips.cc/Conferences/2015/tutorialslides/Dally-NIPS-Tutorial-2015.pdf) diff --git a/PaddleSlim/docs/usage.md b/PaddleSlim/docs/usage.md index 48069bc30a078317e3d6d4e7298f1f7251691722..6733f7512745a7f91afccc60e996fe8e23dddf6c 100644 --- a/PaddleSlim/docs/usage.md +++ b/PaddleSlim/docs/usage.md @@ -18,7 +18,7 @@ --- # Paddle模型压缩工具库使用说明 -本文第一章介绍PaddleSlim模块通用功能的使用,不涉及具体压缩策略的细节。第二、三、四章分别介绍量化训练、剪切、蒸馏三种压缩策略的使用方式。 +本文第一章介绍PaddleSlim模块通用功能的使用,不涉及具体压缩策略的细节。第二章分别用4小节介绍量化训练、剪裁、蒸馏和轻量级模型结构搜索四种压缩策略的使用方式。 建议在看具体策略使用方式之前,先浏览下对应的原理介绍:算法原理介绍 >在本文中不区分operator和layer的概念。不区分loss和cost的概念。 @@ -27,8 +27,9 @@ - [通用功能使用说明](#1-paddleslim通用功能使用介绍) - [量化使用说明](#21-量化训练) -- [剪切使用说明](#22-卷积核剪切) +- [剪裁使用说明](#22-模型通道剪裁) - [蒸馏使用说明](#23-蒸馏) +- [轻量级模型结构搜索使用说明](#24-轻量级模型结构搜索) ## 1. PaddleSlim通用功能使用介绍 @@ -85,7 +86,7 @@ #### 1.1.2.4. load pretrain model -- 剪切:需要加载pretrain model +- 剪裁:需要加载pretrain model - 蒸馏:根据需要选择是否加载pretrain model - 量化训练:需要加载pretrain model @@ -171,8 +172,8 @@ pruners: '*': 'l1_norm' ``` -第二步:注册剪切策略 -如下所示,我们注册两个uniform剪切策略,分别在第0个epoch和第10个epoch将模型的FLOPS剪掉10%. +第二步:注册剪裁策略 +如下所示,我们注册两个uniform剪裁策略,分别在第0个epoch和第10个epoch将模型的FLOPS剪掉10%. ```python strategies: pruning_strategy_0: @@ -207,10 +208,10 @@ compress_pass: ## 2. 模型压缩策略使用介绍 -本章依次介绍量化训练、卷积核剪切和蒸馏三种策略的使用方式,在此之前建议先浏览相应策略的原理介绍: +本章依次介绍量化训练、模型通道剪裁和蒸馏三种策略的使用方式,在此之前建议先浏览相应策略的原理介绍: - [量化训练原理](tutorial.md#1-quantization-aware-training量化介绍) -- [卷积核剪切原理](tutorial.md#2-卷积核剪切原理) +- [模型通道剪裁原理](tutorial.md#2-模型通道剪裁原理) - [蒸馏原理](tutorial.md#3-蒸馏) ### 2.1 量化训练 @@ -288,14 +289,14 @@ strategies: 量化训练High-Level API是对Low-Level API的高层次封装,这使得用户仅需编写少量的代码和配置文件即可进行量化训练。然而,封装必然会带来使用灵活性的降低。因此,若用户在进行量化训练时需要更多的灵活性,可参考 [量化训练Low-Level API使用示例](../quant_low_level_api/README.md) 。 -### 2.2 卷积核剪切 -该策略通过减少指定卷积层中卷积核的数量,达到缩减模型大小和计算复杂度的目的。根据选取剪切比例的策略的不同,又细分为以下两个方式: +### 2.2 模型通道剪裁 +该策略通过减少指定卷积层中卷积核的数量,达到缩减模型大小和计算复杂度的目的。根据选取剪裁比例的策略的不同,又细分为以下两个方式: -- uniform pruning: 每层剪切掉相同比例的卷积核数量。 -- sensitive pruning: 根据每层敏感度,剪切掉不同比例的卷积核数量。 +- uniform pruning: 每层剪裁掉相同比例的卷积核数量。 +- sensitive pruning: 根据每层敏感度,剪裁掉不同比例的卷积核数量。 -两种剪切方式都需要加载预训练模型。 -卷积核剪切是基于结构剪切,所以在配置文件中需要注册一个`StructurePruner`, 如下所示: +两种剪裁方式都需要加载预训练模型。 +通道剪裁是基于结构剪裁,所以在配置文件中需要注册一个`StructurePruner`, 如下所示: ``` pruners: @@ -310,13 +311,13 @@ pruners: 其中,一个配置文件可注册多个pruners, 所有pruner需要放在`pruners`关键字下, `pruner`的可配置参数有: - **class:** pruner 的类型,目前只支持`StructurePruner` -- **pruning_axis:** 剪切的纬度;'`conv*': 0`表示对所有的卷积层filter weight的第0维进行剪切,即对卷积层filter的数量进行剪切。 -- **criterions**: 通过通配符指定剪切不同parameter时用的排序方式。目前仅支持`l1_norm`. +- **pruning_axis:** 剪裁的纬度;'`conv*': 0`表示对所有的卷积层filter weight的第0维进行剪裁,即对卷积层filter的数量进行剪裁。 +- **criterions**: 通过通配符指定剪裁不同parameter时用的排序方式。目前仅支持`l1_norm`. #### 2.2.1 uniform pruning -uniform pruning剪切策略需要在配置文件的`strategies`关键字下注册`UniformPruneStrategy`实例,并将其添加至compressor的strategies列表中。 +uniform pruning剪裁策略需要在配置文件的`strategies`关键字下注册`UniformPruneStrategy`实例,并将其添加至compressor的strategies列表中。 如下所示: ``` strategies: @@ -333,17 +334,17 @@ compressor: ``` UniformPruneStrategy的可配置参数有: -- **class:** 如果使用Uniform剪切策略,请设置为`UniformPruneStrategy` -- **pruner:** StructurePruner实例的名称,需要在配置文件中注册。在pruner中指定了对单个parameter的剪切方式。 -- **start_epoch:** 开始剪切策略的epoch. 在start_epoch开始之前,该策略会对网络中的filter数量进行剪切,从start_epoch开始对被剪切的网络进行fine-tune训练,直到整个压缩任务结束。 +- **class:** 如果使用Uniform剪裁策略,请设置为`UniformPruneStrategy` +- **pruner:** StructurePruner实例的名称,需要在配置文件中注册。在pruner中指定了对单个parameter的剪裁方式。 +- **start_epoch:** 开始剪裁策略的epoch. 在start_epoch开始之前,该策略会对网络中的filter数量进行剪裁,从start_epoch开始对被剪裁的网络进行fine-tune训练,直到整个压缩任务结束。 - **target_ratio:** 将目标网络的FLOPS剪掉的比例。 -- **pruned_params:** 被剪切的parameter的名称,支持通配符。如,‘*’为对所有parameter进行剪切,‘conv*’意为对所有名义以‘conv’开头的parameter进行剪切。 +- **pruned_params:** 被剪裁的parameter的名称,支持通配符。如,‘*’为对所有parameter进行剪裁,‘conv*’意为对所有名义以‘conv’开头的parameter进行剪裁。 #### 2.2.2 sensitive pruning -sensitive剪切策略需要在配置文件的`strategies`关键字下注册`SensitivePruneStrategy`实例,并将其添加至compressor的strategies列表中。 +sensitive剪裁策略需要在配置文件的`strategies`关键字下注册`SensitivePruneStrategy`实例,并将其添加至compressor的strategies列表中。 如下所示: ``` strategies: @@ -365,14 +366,70 @@ compressor: ``` SensitivePruneStrategy可配置的参数有: -- **class:** 如果使用敏感度剪切策略,请设置为`SensitivePruneStrategy` -- **pruner:** StructurePruner实例的名称,需要在配置文件中注册。在pruner中指定了对单个parameter的剪切方式。 -- **start_epoch:** 开始剪切策略的epoch。 在start_epoch开始之前,该策略会对网络中的filter数量进行第一次剪切。 -- **delta_rate:** 统计敏感度信息时,剪切率从0到1,依次递增delta_rate. 具体细节可参考[原理介绍文档]() +- **class:** 如果使用敏感度剪裁策略,请设置为`SensitivePruneStrategy` +- **pruner:** StructurePruner实例的名称,需要在配置文件中注册。在pruner中指定了对单个parameter的剪裁方式。 +- **start_epoch:** 开始剪裁策略的epoch。 在start_epoch开始之前,该策略会对网络中的filter数量进行第一次剪裁。 +- **delta_rate:** 统计敏感度信息时,剪裁率从0到1,依次递增delta_rate. 具体细节可参考[原理介绍文档]() - **target_ratio:** 将目标网络的FLOPS剪掉的比例。 -- **num_steps:** 整个剪切过程的步数。每次迭代剪掉的比例为:$step = 1 - (1-target\_ratio)^{\frac{1}{num\_steps}}$ -- **eval_rate:** 计算敏感度时,随机抽取使用的验证数据的比例。在迭代剪切中,为了快速重新计算每一步的每个parameter的敏感度,建议随机选取部分验证数据进行计算。当`num_steps`等于1时,建议使用全量数据进行计算。 +- **num_steps:** 整个剪裁过程的步数。每次迭代剪掉的比例为:$step = 1 - (1-target\_ratio)^{\frac{1}{num\_steps}}$ +- **eval_rate:** 计算敏感度时,随机抽取使用的验证数据的比例。在迭代剪裁中,为了快速重新计算每一步的每个parameter的敏感度,建议随机选取部分验证数据进行计算。当`num_steps`等于1时,建议使用全量数据进行计算。 +#### 2.2.3 auto filter pruning + +该策略使用模拟退火算法搜索得到一组剪裁率,按搜索到的这组剪裁率剪裁网络,并对剪裁后的网络进行训练。 + +自动通道剪裁策略需要在配置文件的`strategies`关键字下注册`AutoPruneStrategy`实例,并将其添加至compressor的strategies列表中。 +如下所示: +``` +strategies: + auto_pruning_strategy: + class: 'AutoPruneStrategy' + pruner: 'pruner_1' + controller: 'sa_controller' + start_epoch: 0 + end_epoch: 500 + retrain_epoch: 0 + max_ratio: 0.50 + min_ratio: 0.48 + uniform_range: 0.4 + pruned_params: '.*_sep_weights' + metric_name: 'acc_top1' +compressor: + epoch: 500 + checkpoint_path: './checkpoints/' + strategies: + - auto_pruning_strategy +``` +AutoPruneStrategy可配置的参数有: + +- **class:** 如果使用自动通道剪裁策略,请设置为`AutoPruneStrategy`。 +- **pruner:** StructurePruner实例的名称,需要在配置文件中注册。在pruner中指定了对单个parameter的剪裁方式。 +- **controller:** 用于搜索的controller, 需要在当前配置文件提前注册,下文会详细介绍其注册方法。 + +- **start_epoch:** 开始搜索剪裁率组合的的epoch。 +- **end_epoch:** 结束搜索剪裁率组合的epoch。 在end_epoch,该策略会根据当前搜索到的最好的剪裁率组合对网络进行剪裁。 + +- **retrain_epoch:** 评估一个模型性能之前,需要训练的epoch的数量。默认为0。 +- **max_ratio:** 剪掉FLOPS的最高比例。 +- **target_ratio:** 剪掉FLOPS的最低比例。 +- **uniform_range:** 每个Parameter最多允许被剪掉的比例。 +- **pruned_params:** 被剪裁的parameter的名称,支持通配符。如,‘*’为对所有parameter进行剪裁,‘conv*’意为对所有名义以‘conv’开头的parameter进行剪裁。 +- **metric_name:** 评估模型性能的指标。 + +controller的配置方式如下: + +``` +controllers: + sa_controller: + class: 'SAController' + reduce_rate: 0.85 + init_temperature: 10.24 + max_iter_number: 300 +``` +- **class:** distiller类名称,当前可选:`SAController`。 +- **reduce_rate:** float类型;温度的衰减率。 +- **init_temperature:** float类型;初始化温度。 +- **max_iter_number:** int类型;在得到一个满足FLOPS限制的tokens之前,最多尝试的次数。 ### 2.3 蒸馏 @@ -452,3 +509,92 @@ distillers: - **student_temperature:** 在计算softmax_with_cross_entropy之前,用该系数除student_feature_map。 - **teacher_temperature:** 在计算softmax_with_cross_entropy之前,用该系数除teacher_feature_map。 - **distillation_loss_weight:** 当前定义的loss对应的权重。默认为1.0 + + +### 2.4 轻量级模型结构搜索 + +该功能基于模拟退火算法,实现了轻量级模型结构的快速搜索,简称为LightNAS(Light Network Architecture Search). + +使用改功能,需要用户做两个工作: + +- 定义搜索空间 +- 配置LightNASStrategy,并启动压缩任务 + +#### 2.4.1 定义搜索空间 + +用户需要通过继承[SearchSpace类](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/fluid/contrib/slim/nas/search_space.py#L19)并重写其方法来定义搜索空间。用户需要重写实现的方法有: + +- init_tokens: tokens以数组的形式格式表示网络结构,一个tokens对应一个网络结构。init_tokens指搜索的初始化tokens. + +- range_table: 以数组的形式指定tokens数组中每个位置的取值范围,其长度与tokens长度相同。tokens[i]的取值范围为[0, range_table[i]). + +- create_net: 根据指定的tokens构造初始化Program、训练Program和测试Program. + +在[PaddlePaddle/models/light_nas](https://github.com/PaddlePaddle/models/blob/develop/PaddleSlim/light_nas/light_nas_space.py)下,定义了经过验证的一个搜索空间,建议一般用户直接用该搜索空间。 + +在构造Compressor对象时,按以下方式将SearchSpace实例传入: + +``` +... +space = LightNASSpace() +... +com_pass = Compressor( + place, + fluid.global_scope(), + train_prog, + train_reader=train_reader, + train_feed_list=None, + train_fetch_list=train_fetch_list, + eval_program=test_prog, + eval_reader=test_reader, + eval_feed_list=None, + eval_fetch_list=val_fetch_list, + train_optimizer=None, + search_space=space) +``` + + +#### 2.4.2 配置LightNASStrategy + +在配置文件中,配置搜索策略方式如下: +``` +strategies: + light_nas_strategy: + class: 'LightNASStrategy' + controller: 'sa_controller' + target_flops: 592948064 + end_epoch: 500 + retrain_epoch: 5 + metric_name: 'acc_top1' + server_ip: '' + server_port: 8871 + is_server: True + search_steps: 100 +``` +其中, 需要在关键字`strategies`下注册策略实例,可配置参数有: + +- **class:** 策略类的名称,轻量级模型结构搜索策略请设置为LightNASStrategy。 +- **controller:** 用于搜索的controller, 需要在当前配置文件提前注册,下文会详细介绍其注册方法。 +- **target_flops:** FLOPS限制,搜索出的网络结构的FLOPS不超过该数值。 +- **end_epoch:** 当前client结束搜索策略的epoch。 +- **retrain_epoch:** 在评估模型结构性能之前,需要训练的epoch数量。(end_epoch-0)/retrain_epoch为当前client搜索出的网络结构的数量。 +- **metric_name:** 评估模型性能的指标。 +- **server_ip:** 指定controller server的ip。默认为空,即自动获取当前机器的ip。 +- **server_port:** 指定controller server监听的端口。 +- **is_server:** 以当前配置文件启动的进程是否包含controller server. 整个搜索任务必须有且只有一个controller server。 +- **search_steps:** controller server搜索的步数,也就是server产出的网络结构的数量。 + +controller的配置方式如下: + +``` +controllers: + sa_controller: + class: 'SAController' + reduce_rate: 0.85 + init_temperature: 10.24 + max_iter_number: 300 +``` +- **class:** distiller类名称,当前可选:`SAController`。 +- **reduce_rate:** float类型;温度的衰减率。 +- **init_temperature:** float类型;初始化温度。 +- **max_iter_number:** int类型;在得到一个满足FLOPS限制的tokens之前,最多尝试的次数。