diff --git a/docs/README.md b/docs/README.md index e2ee67216a6cdf98941d0c51afbb88a562ae0b25..6a2b4d9d2c32544b7da55b97fab1c567d5e2d136 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# PaddleSlim文档构建与发布教程 +# 文档构建与发布教程 ## 1. 文档构成 @@ -70,7 +70,16 @@ make html 以上命令生成`html`文件到路径`./build/html/`。 -## 2.2 编译英文文档 + +## 2.2 预览文档 + +进入`PaddleSlim/docs/zh_cn/build/html`路径下。 +执行`python -m SimpleHTTPServer 8883`。 +假设当前机器IP为`server_ip`。 + +通过浏览器查看链接`server_ip:8883`即可预览文档。 + +## 2.3 编译英文文档 进入路径`PaddleSlim/docs/en` @@ -123,6 +132,6 @@ git commit -m "update pages" git push origin gh-pages ``` -# 4. 其它 +## 4. 其它 英文API文档格式请参考:https://wanghaoshuang.github.io/PaddleSlim/api_en/paddleslim.analysis.html diff --git a/docs/en/Makefile b/docs/en/Makefile index 141d0b25f71fd0d96f59c5f682ea537d2ba767ea..cba75daa34d7abc601401142fcb7c84d62505652 100644 --- a/docs/en/Makefile +++ b/docs/en/Makefile @@ -17,3 +17,4 @@ help: # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + rm -rf $(BUILDDIR)/html/index.html diff --git a/docs/zh_cn/Makefile b/docs/zh_cn/Makefile index 141d0b25f71fd0d96f59c5f682ea537d2ba767ea..d7625935379669d6b18b382c87cf9ff5de5041f1 100644 --- a/docs/zh_cn/Makefile +++ b/docs/zh_cn/Makefile @@ -17,3 +17,4 @@ help: # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + rm -rf $(BUILDDIR)/$@/index_en.html diff --git a/docs/zh_cn/api_cn/analysis_api.md b/docs/zh_cn/api_cn/analysis_api.md deleted file mode 100644 index ccd165bdae6a2d309776f6fb9215ecdbdee97787..0000000000000000000000000000000000000000 --- a/docs/zh_cn/api_cn/analysis_api.md +++ /dev/null @@ -1,168 +0,0 @@ -# 模型分析 - -## FLOPs -paddleslim.analysis.flops(program, detail=False) [源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/analysis/flops.py) - -: 获得指定网络的浮点运算次数(FLOPs)。 - -**参数:** - -- **program(paddle.fluid.Program)** - 待分析的目标网络。更多关于Program的介绍请参考:[Program概念介绍](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Program_cn.html#program)。 - -- **detail(bool)** - 是否返回每个卷积层的FLOPs。默认为False。 - -- **only_conv(bool)** - 如果设置为True,则仅计算卷积层和全连接层的FLOPs,即浮点数的乘加(multiplication-adds)操作次数。如果设置为False,则也会计算卷积和全连接层之外的操作的FLOPs。 - -**返回值:** - -- **flops(float)** - 整个网络的FLOPs。 - -- **params2flops(dict)** - 每层卷积对应的FLOPs,其中key为卷积层参数名称,value为FLOPs值。 - -**示例:** - -```python -import paddle.fluid as fluid -from paddle.fluid.param_attr import ParamAttr -from paddleslim.analysis import flops - -def conv_bn_layer(input, - num_filters, - filter_size, - name, - stride=1, - groups=1, - act=None): - conv = fluid.layers.conv2d( - input=input, - num_filters=num_filters, - filter_size=filter_size, - stride=stride, - padding=(filter_size - 1) // 2, - groups=groups, - act=None, - param_attr=ParamAttr(name=name + "_weights"), - bias_attr=False, - name=name + "_out") - bn_name = name + "_bn" - return fluid.layers.batch_norm( - input=conv, - act=act, - name=bn_name + '_output', - param_attr=ParamAttr(name=bn_name + '_scale'), - bias_attr=ParamAttr(bn_name + '_offset'), - moving_mean_name=bn_name + '_mean', - moving_variance_name=bn_name + '_variance', ) - -main_program = fluid.Program() -startup_program = fluid.Program() -# X X O X O -# conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 -# | ^ | ^ -# |____________| |____________________| -# -# X: prune output channels -# O: prune input channels -with fluid.program_guard(main_program, startup_program): - input = fluid.data(name="image", shape=[None, 3, 16, 16]) - conv1 = conv_bn_layer(input, 8, 3, "conv1") - conv2 = conv_bn_layer(conv1, 8, 3, "conv2") - sum1 = conv1 + conv2 - conv3 = conv_bn_layer(sum1, 8, 3, "conv3") - conv4 = conv_bn_layer(conv3, 8, 3, "conv4") - sum2 = conv4 + sum1 - conv5 = conv_bn_layer(sum2, 8, 3, "conv5") - conv6 = conv_bn_layer(conv5, 8, 3, "conv6") - -print("FLOPs: {}".format(flops(main_program))) -``` - -## model_size -paddleslim.analysis.model_size(program) [源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/analysis/model_size.py) - -获得指定网络的参数数量。 - -**参数:** - -- **program(paddle.fluid.Program)** - 待分析的目标网络。更多关于Program的介绍请参考:[Program概念介绍](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Program_cn.html#program)。 - -**返回值:** - -- **model_size(int)** - 整个网络的参数数量。 - -**示例:** - -```python -import paddle.fluid as fluid -from paddle.fluid.param_attr import ParamAttr -from paddleslim.analysis import model_size - -def conv_layer(input, - num_filters, - filter_size, - name, - stride=1, - groups=1, - act=None): - conv = fluid.layers.conv2d( - input=input, - num_filters=num_filters, - filter_size=filter_size, - stride=stride, - padding=(filter_size - 1) // 2, - groups=groups, - act=None, - param_attr=ParamAttr(name=name + "_weights"), - bias_attr=False, - name=name + "_out") - return conv - -main_program = fluid.Program() -startup_program = fluid.Program() -# X X O X O -# conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 -# | ^ | ^ -# |____________| |____________________| -# -# X: prune output channels -# O: prune input channels -with fluid.program_guard(main_program, startup_program): - input = fluid.data(name="image", shape=[None, 3, 16, 16]) - conv1 = conv_layer(input, 8, 3, "conv1") - conv2 = conv_layer(conv1, 8, 3, "conv2") - sum1 = conv1 + conv2 - conv3 = conv_layer(sum1, 8, 3, "conv3") - conv4 = conv_layer(conv3, 8, 3, "conv4") - sum2 = conv4 + sum1 - conv5 = conv_layer(sum2, 8, 3, "conv5") - conv6 = conv_layer(conv5, 8, 3, "conv6") - -print("FLOPs: {}".format(model_size(main_program))) -``` - -## TableLatencyEvaluator -paddleslim.analysis.TableLatencyEvaluator(table_file, delimiter=",") [源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/analysis/latency.py) - -: 基于硬件延时表的模型延时评估器。 - -**参数:** - -- **table_file(str)** - 所使用的延时评估表的绝对路径。关于演示评估表格式请参考:[PaddleSlim硬件延时评估表格式](../paddleslim/analysis/table_latency.md) - -- **delimiter(str)** - 硬件延时评估表中,操作信息之前所使用的分割符,默认为英文字符逗号。 - -**返回值:** - -- **Evaluator** - 硬件延时评估器的实例。 - -paddleslim.analysis.TableLatencyEvaluator.latency(graph) [源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/analysis/latency.py) - -: 获得指定网络的预估延时。 - -**参数:** - -- **graph(Program)** - 待预估的目标网络。 - -**返回值:** - -- **latency** - 目标网络的预估延时。 diff --git a/docs/zh_cn/api_cn/analysis_api.rst b/docs/zh_cn/api_cn/analysis_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..0f0bebf4dccf09114d607a8d02179a88cdb53cd1 --- /dev/null +++ b/docs/zh_cn/api_cn/analysis_api.rst @@ -0,0 +1,181 @@ +模型分析 +======= + +FLOPs +----- + +.. py:function:: paddleslim.analysis.flops(program, detail=False) + +`源代码 `_ + +获得指定网络的浮点运算次数(FLOPs)。 + +**参数:** + +- **program(paddle.fluid.Program)** - 待分析的目标网络。更多关于Program的介绍请参考:`Program概念介绍 `_。 + +- **detail(bool)** - 是否返回每个卷积层的FLOPs。默认为False。 + +- **only_conv(bool)** - 如果设置为True,则仅计算卷积层和全连接层的FLOPs,即浮点数的乘加(multiplication-adds)操作次数。如果设置为False,则也会计算卷积和全连接层之外的操作的FLOPs。 + +**返回值:** + +- **flops(float)** - 整个网络的FLOPs。 + +- **params2flops(dict)** - 每层卷积对应的FLOPs,其中key为卷积层参数名称,value为FLOPs值。 + +**示例:** + +.. code-block:: python + + import paddle.fluid as fluid + from paddle.fluid.param_attr import ParamAttr + from paddleslim.analysis import flops + + def conv_bn_layer(input, + num_filters, + filter_size, + name, + stride=1, + groups=1, + act=None): + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) // 2, + groups=groups, + act=None, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=False, + name=name + "_out") + bn_name = name + "_bn" + return fluid.layers.batch_norm( + input=conv, + act=act, + name=bn_name + '_output', + param_attr=ParamAttr(name=bn_name + '_scale'), + bias_attr=ParamAttr(bn_name + '_offset'), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance', ) + + main_program = fluid.Program() + startup_program = fluid.Program() + # X X O X O + # conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 + # | ^ | ^ + # |____________| |____________________| + # + # X: prune output channels + # O: prune input channels + with fluid.program_guard(main_program, startup_program): + input = fluid.data(name="image", shape=[None, 3, 16, 16]) + conv1 = conv_bn_layer(input, 8, 3, "conv1") + conv2 = conv_bn_layer(conv1, 8, 3, "conv2") + sum1 = conv1 + conv2 + conv3 = conv_bn_layer(sum1, 8, 3, "conv3") + conv4 = conv_bn_layer(conv3, 8, 3, "conv4") + sum2 = conv4 + sum1 + conv5 = conv_bn_layer(sum2, 8, 3, "conv5") + conv6 = conv_bn_layer(conv5, 8, 3, "conv6") + + print("FLOPs: {}".format(flops(main_program))) + +model_size +---------- + +.. py:function:: paddleslim.analysis.model_size(program) + +`源代码 `_ + +获得指定网络的参数数量。 + +**参数:** + +- **program(paddle.fluid.Program)** - 待分析的目标网络。更多关于Program的介绍请参考:`Program概念介绍 `_。 + +**返回值:** + +- **model_size(int)** - 整个网络的参数数量。 + +**示例:** + +.. code-block:: python + + import paddle.fluid as fluid + from paddle.fluid.param_attr import ParamAttr + from paddleslim.analysis import model_size + + def conv_layer(input, + num_filters, + filter_size, + name, + stride=1, + groups=1, + act=None): + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) // 2, + groups=groups, + act=None, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=False, + name=name + "_out") + return conv + + main_program = fluid.Program() + startup_program = fluid.Program() + # X X O X O + # conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 + # | ^ | ^ + # |____________| |____________________| + # + # X: prune output channels + # O: prune input channels + with fluid.program_guard(main_program, startup_program): + input = fluid.data(name="image", shape=[None, 3, 16, 16]) + conv1 = conv_layer(input, 8, 3, "conv1") + conv2 = conv_layer(conv1, 8, 3, "conv2") + sum1 = conv1 + conv2 + conv3 = conv_layer(sum1, 8, 3, "conv3") + conv4 = conv_layer(conv3, 8, 3, "conv4") + sum2 = conv4 + sum1 + conv5 = conv_layer(sum2, 8, 3, "conv5") + conv6 = conv_layer(conv5, 8, 3, "conv6") + + print("FLOPs: {}".format(model_size(main_program))) + +TableLatencyEvaluator +--------------------- + +.. py:class:: paddleslim.analysis.TableLatencyEvaluator(table_file, delimiter=",") + +`源代码 `_ + +基于硬件延时表的模型延时评估器。 + +**参数:** + +- **table_file(str)** - 所使用的延时评估表的绝对路径。关于演示评估表格式请参考:PaddleSlim硬件延时评估表格式 + +- **delimiter(str)** - 在硬件延时评估表中,操作信息之前所使用的分割符,默认为英文字符逗号。 + +**返回值:** + +- **Evaluator** - 硬件延时评估器的实例。 + + .. py:method:: latency(graph) + + 获得指定网络的预估延时。 + + **参数:** + + - **graph(Program)** - 待预估的目标网络。 + + **返回值:** + + - **latency** - 目标网络的预估延时。 diff --git a/docs/zh_cn/api_cn/index.rst b/docs/zh_cn/api_cn/index.rst index 8d76711c44fa07c094dff87e7d0a899028559f3a..722949487fcda71f65a48ae6873b76a85f8eb319 100644 --- a/docs/zh_cn/api_cn/index.rst +++ b/docs/zh_cn/api_cn/index.rst @@ -9,12 +9,12 @@ API文档 .. toctree:: :maxdepth: 1 - analysis_api.md - nas_api.md - one_shot_api.md + analysis_api.rst + nas_api.rst + one_shot_api.rst pantheon_api.md - prune_api.md - quantization_api.md - single_distiller_api.md + prune_api.rst + quantization_api.rst + single_distiller_api.rst search_space.md table_latency.md diff --git a/docs/zh_cn/api_cn/nas_api.md b/docs/zh_cn/api_cn/nas_api.md deleted file mode 100644 index a7950ec00de4d18c5eed8b75461743d653efba66..0000000000000000000000000000000000000000 --- a/docs/zh_cn/api_cn/nas_api.md +++ /dev/null @@ -1,132 +0,0 @@ -# SA-NAS - -## 搜索空间参数的配置 -通过参数配置搜索空间。更多搜索空间的使用可以参考[search_space](../search_space.md) - -**参数:** - -- **input_size(int|None)**:- `input_size`表示输入feature map的大小。`input_size`和`output_size`用来计算整个模型结构中下采样次数。 -- **output_size(int|None)**:- `output_size`表示输出feature map的大小。`input_size`和`output_size`用来计算整个模型结构中下采样次数。 -- **block_num(int|None)**:- `block_num`表示搜索空间中block的数量。 -- **block_mask(list|None)**:- `block_mask`是一组由0、1组成的列表,0表示当前block是normal block,1表示当前block是reduction block。reduction block表示经过这个block之后的feature map大小下降为之前的一半,normal block表示经过这个block之后feature map大小不变。如果设置了`block_mask`,则主要以`block_mask`为主要配置,`input_size`,`output_size`和`block_num`三种配置是无效的。 - -## SANAS - -paddleslim.nas.SANAS(configs, server_addr=("", 8881), init_temperature=None, reduce_rate=0.85, init_tokens=None, search_steps=300, save_checkpoint='./nas_checkpoint', load_checkpoint=None, is_server=True)[源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/nas/sa_nas.py#L36) -: SANAS(Simulated Annealing Neural Architecture Search)是基于模拟退火算法进行模型结构搜索的算法,一般用于离散搜索任务。 - -**参数:** - -- **configs(list)** - 搜索空间配置列表,格式是`[(key, {input_size, output_size, block_num, block_mask})]`或者`[(key)]`(MobileNetV2、MobilenetV1和ResNet的搜索空间使用和原本网络结构相同的搜索空间,所以仅需指定`key`即可), `input_size` 和`output_size`表示输入和输出的特征图的大小,`block_num`是指搜索网络中的block数量,`block_mask`是一组由0和1组成的列表,0代表不进行下采样的block,1代表下采样的block。 更多paddleslim提供的搜索空间配置可以参考[Search Space](../search_space.md)。 -- **server_addr(tuple)** - SANAS的地址,包括server的ip地址和端口号,如果ip地址为None或者为""的话则默认使用本机ip。默认:("", 8881)。 -- **init_temperature(float)** - 基于模拟退火进行搜索的初始温度。如果init_template为None而且init_tokens为None,则默认初始温度为10.0,如果init_template为None且init_tokens不为None,则默认初始温度为1.0。详细的温度设置可以参考下面的Note。默认:None。 -- **reduce_rate(float)** - 基于模拟退火进行搜索的衰减率。详细的退火率设置可以参考下面的Note。默认:0.85。 -- **init_tokens(list|None)** - 初始化token,若init_tokens为空,则SA算法随机生成初始化tokens。默认:None。 -- **search_steps(int)** - 搜索过程迭代的次数。默认:300。 -- **save_checkpoint(str|None)** - 保存checkpoint的文件目录,如果设置为None的话则不保存checkpoint。默认:`./nas_checkpoint`。 -- **load_checkpoint(str|None)** - 加载checkpoint的文件目录,如果设置为None的话则不加载checkpoint。默认:None。 -- **is_server(bool)** - 当前实例是否要启动一个server。默认:True。 - -**返回:** -一个SANAS类的实例 - -**示例代码:** -```python -from paddleslim.nas import SANAS -config = [('MobileNetV2Space')] -sanas = SANAS(configs=config) -``` - -!!! note "Note" - - 初始化温度和退火率的意义:
- - SA算法内部会保存一个基础token(初始化token可以自己传入也可以随机生成)和基础score(初始化score为-1),下一个token会在当前SA算法保存的token的基础上产生。在SA的搜索过程中,如果本轮的token训练得到的score大于SA算法中保存的score,则本轮的token一定会被SA算法接收保存为下一轮token产生的基础token。
- - 初始温度越高表示SA算法当前处的阶段越不稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越大。
- - 初始温度越低表示SA算法当前处的阶段越稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越小。
- - 退火率越大,表示SA算法收敛的越慢,即SA算法越慢到稳定阶段。
- - 退火率越低,表示SA算法收敛的越快,即SA算法越快到稳定阶段。
- - - 初始化温度和退火率的设置:
- - 如果原本就有一个较好的初始化token,想要基于这个较好的token来进行搜索的话,SA算法可以处于一个较为稳定的状态进行搜索r这种情况下初始温度可以设置的低一些,例如设置为1.0,退火率设置的大一些,例如设置为0.85。如果想要基于这个较好的token利用贪心算法进行搜索,即只有当本轮token训练得到的score大于SA算法中保存的score,SA算法才接收本轮token,则退火率可设置为一个极小的数字,例如设置为0.85 ** 10。
- - 初始化token如果是随机生成的话,代表初始化token是一个比较差的token,SA算法可以处于一种不稳定的阶段进行搜索,尽可能的随机探索所有可能得token,从而找到一个较好的token。初始温度可以设置的高一些,例如设置为1000,退火率相对设置的小一些。 - - -paddleslim.nas.SANAS.next_archs() -: 获取下一组模型结构。 - -**返回:** -返回模型结构实例的列表,形式为list。 - -**示例代码:** -```python -import paddle.fluid as fluid -from paddleslim.nas import SANAS -config = [('MobileNetV2Space')] -sanas = SANAS(configs=config) -input = fluid.data(name='input', shape=[None, 3, 32, 32], dtype='float32') -archs = sanas.next_archs() -for arch in archs: - output = arch(input) - input = output -print(output) -``` - -paddleslim.nas.SANAS.reward(score) -: 把当前模型结构的得分情况回传。 - -**参数:** - -- **score:** - 当前模型的得分,分数越大越好。 - -**返回:** -模型结构更新成功或者失败,成功则返回`True`,失败则返回`False`。 - -**示例代码:** -```python -import paddle.fluid as fluid -from paddleslim.nas import SANAS -config = [('MobileNetV2Space')] -sanas = SANAS(configs=config) -archs = sanas.next_archs() - -### 假设网络计算出来的score是1,实际代码中使用时需要返回真实score。 -score=float(1.0) -sanas.reward(float(score)) -``` - - -paddleslim.nas.SANAS.tokens2arch(tokens) -: 通过一组tokens得到实际的模型结构,一般用来把搜索到最优的token转换为模型结构用来做最后的训练。tokens的形式是一个列表,tokens映射到搜索空间转换成相应的网络结构,一组tokens对应唯一的一个网络结构。 - -**参数:** - -- **tokens(list):** - 一组tokens。tokens的长度和范取决于搜索空间。 - -**返回:** -根据传入的token得到一个模型结构实例。 - -**示例代码:** -```python -import paddle.fluid as fluid -from paddleslim.nas import SANAS -config = [('MobileNetV2Space')] -sanas = SANAS(configs=config) -input = fluid.data(name='input', shape=[None, 3, 32, 32], dtype='float32') -tokens = ([0] * 25) -archs = sanas.tokens2arch(tokens)[0] -print(archs(input)) -``` - -paddleslim.nas.SANAS.current_info() -: 返回当前token和搜索过程中最好的token和reward。 - -**返回:** -搜索过程中最好的token,reward和当前训练的token,形式为dict。 - -**示例代码:** -```python -import paddle.fluid as fluid -from paddleslim.nas import SANAS -config = [('MobileNetV2Space')] -sanas = SANAS(configs=config) -print(sanas.current_info()) -``` diff --git a/docs/zh_cn/api_cn/nas_api.rst b/docs/zh_cn/api_cn/nas_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..b4b0d38abfdfd35b40e1f6fa5ab919aabd4a1407 --- /dev/null +++ b/docs/zh_cn/api_cn/nas_api.rst @@ -0,0 +1,160 @@ +SA-NAS +======== + +搜索空间参数的配置 +---------------------- + + +通过参数配置搜索空间。更多搜索空间的使用可以参考: [search_space](../search_space.md) + +**参数:** + +- **input_size(int|None)**:- ``input_size`` 表示输入 ``feature map`` 的大小。 ``input_size`` 和 ``output_size`` 用来计算整个模型结构中下采样次数。 + +- **output_size(int|None)**:- ``output_size`` 表示输出feature map的大小。 ``input_size`` 和 ``output_size`` 用来计算整个模型结构中下采样次数。 + +- **block_num(int|None)**:- ``block_num`` 表示搜索空间中block的数量。 + +- **block_mask(list|None)**:- ``block_mask`` 是一组由0、1组成的列表,0表示当前block是normal block,1表示当前block是reduction block。reduction block表示经过这个block之后的feature map大小下降为之前的一半,normal block表示经过这个block之后feature map大小不变。如果设置了 ``block_mask`` ,则主要以 ``block_mask`` 为主要配置, ``input_size`` , ``output_size`` 和 ``block_num`` 三种配置是无效的。 + +SANAS +------ + +.. py:class:: paddleslim.nas.SANAS(configs, server_addr=("", 8881), init_temperature=None, reduce_rate=0.85, init_tokens=None, search_steps=300, save_checkpoint='./nas_checkpoint', load_checkpoint=None, is_server=True) + +`源代码 `_ + +SANAS(Simulated Annealing Neural Architecture Search)是基于模拟退火算法进行模型结构搜索的算法,一般用于离散搜索任务。 + +**参数:** + +- **configs(list)** - 搜索空间配置列表,格式是 ``[(key, {input_size, output_size, block_num, block_mask})]`` 或者 ``[(key)]`` (MobileNetV2、MobilenetV1和ResNet的搜索空间使用和原本网络结构相同的搜索空间,所以仅需指定 ``key`` 即可), ``input_size`` 和 ``output_size`` 表示输入和输出的特征图的大小, ``block_num`` 是指搜索网络中的block数量, ``block_mask`` 是一组由0和1组成的列表,0代表不进行下采样的block,1代表下采样的block。 更多paddleslim提供的搜索空间配置可以参考[Search Space](../search_space.md)。 +- **server_addr(tuple)** - SANAS的地址,包括server的ip地址和端口号,如果ip地址为None或者为""的话则默认使用本机ip。默认:("", 8881)。 +- **init_temperature(float)** - 基于模拟退火进行搜索的初始温度。如果init_template为None而且init_tokens为None,则默认初始温度为10.0,如果init_template为None且init_tokens不为None,则默认初始温度为1.0。详细的温度设置可以参考下面的Note。默认:None。 +- **reduce_rate(float)** - 基于模拟退火进行搜索的衰减率。详细的退火率设置可以参考下面的Note。默认:0.85。 +- **init_tokens(list|None)** - 初始化token,若init_tokens为空,则SA算法随机生成初始化tokens。默认:None。 +- **search_steps(int)** - 搜索过程迭代的次数。默认:300。 +- **save_checkpoint(str|None)** - 保存checkpoint的文件目录,如果设置为None的话则不保存checkpoint。默认: ``./nas_checkpoint`` 。 +- **load_checkpoint(str|None)** - 加载checkpoint的文件目录,如果设置为None的话则不加载checkpoint。默认:None。 +- **is_server(bool)** - 当前实例是否要启动一个server。默认:True。 + +**返回:** +一个SANAS类的实例 + +**示例代码:** + +.. code-block:: python + + from paddleslim.nas import SANAS + config = [('MobileNetV2Space')] + sanas = SANAS(configs=config) + +.. note:: + + - 初始化温度和退火率的意义: + + - SA算法内部会保存一个基础token(初始化token可以自己传入也可以随机生成)和基础score(初始化score为-1),下一个token会在当前SA算法保存的token的基础上产生。在SA的搜索过程中,如果本轮的token训练得到的score大于SA算法中保存的score,则本轮的token一定会被SA算法接收保存为下一轮token产生的基础token。 + + - 初始温度越高表示SA算法当前处的阶段越不稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越大。 + + - 初始温度越低表示SA算法当前处的阶段越稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越小。 + + - 退火率越大,表示SA算法收敛的越慢,即SA算法越慢到稳定阶段。 + + - 退火率越低,表示SA算法收敛的越快,即SA算法越快到稳定阶段。 + + - 初始化温度和退火率的设置: + + - 如果原本就有一个较好的初始化token,想要基于这个较好的token来进行搜索的话,SA算法可以处于一个较为稳定的状态进行搜索r这种情况下初始温度可以设置的低一些,例如设置为1.0,退火率设置的大一些,例如设置为0.85。如果想要基于这个较好的token利用贪心算法进行搜索,即只有当本轮token训练得到的score大于SA算法中保存的score,SA算法才接收本轮token,则退火率可设置为一个极小的数字,例如设置为0.85 ** 10。 + + - 初始化token如果是随机生成的话,代表初始化token是一个比较差的token,SA算法可以处于一种不稳定的阶段进行搜索,尽可能的随机探索所有可能得token,从而找到一个较好的token。初始温度可以设置的高一些,例如设置为1000,退火率相对设置的小一些。 + +.. + + .. py:method:: next_archs() + + 获取下一组模型结构。 + + **返回:** + 返回模型结构实例的列表,形式为list。 + + **示例代码:** + + .. code-block:: python + + import paddle.fluid as fluid + from paddleslim.nas import SANAS + config = [('MobileNetV2Space')] + sanas = SANAS(configs=config) + input = fluid.data(name='input', shape=[None, 3, 32, 32], dtype='float32') + archs = sanas.next_archs() + for arch in archs: + output = arch(input) + input = output + print(output) + + .. py:method:: reward(score) + + 把当前模型结构的得分情况回传。 + + **参数:** + + - **score:** - 当前模型的得分,分数越大越好。 + + **返回:** + 模型结构更新成功或者失败,成功则返回 ``True`` ,失败则返回 ``False`` 。 + + **示例代码:** + + .. code-block:: python + + import paddle.fluid as fluid + from paddleslim.nas import SANAS + config = [('MobileNetV2Space')] + sanas = SANAS(configs=config) + archs = sanas.next_archs() + + ### 假设网络计算出来的score是1,实际代码中使用时需要返回真实score。 + score=float(1.0) + sanas.reward(float(score)) + + + .. py:methd:: tokens2arch(tokens) + + 通过一组tokens得到实际的模型结构,一般用来把搜索到最优的token转换为模型结构用来做最后的训练。tokens的形式是一个列表,tokens映射到搜索空间转换成相应的网络结构,一组tokens对应唯一的一个网络结构。 + + **参数:** + + - **tokens(list):** - 一组tokens。tokens的长度和范取决于搜索空间。 + + **返回:** + 根据传入的token得到一个模型结构实例。 + + **示例代码:** + + .. code-block:: python + + import paddle.fluid as fluid + from paddleslim.nas import SANAS + config = [('MobileNetV2Space')] + sanas = SANAS(configs=config) + input = fluid.data(name='input', shape=[None, 3, 32, 32], dtype='float32') + tokens = ([0] * 25) + archs = sanas.tokens2arch(tokens)[0] + print(archs(input)) + + .. py:method:: current_info() + + 返回当前token和搜索过程中最好的token和reward。 + + **返回:** + 搜索过程中最好的token,reward和当前训练的token,形式为dict。 + + **示例代码:** + + .. code-block:: python + import paddle.fluid as fluid + from paddleslim.nas import SANAS + config = [('MobileNetV2Space')] + sanas = SANAS(configs=config) + print(sanas.current_info()) diff --git a/docs/zh_cn/api_cn/one_shot_api.md b/docs/zh_cn/api_cn/one_shot_api.md deleted file mode 100644 index 825e54599b9d2e077f2269f3b8eb064cd61c3de5..0000000000000000000000000000000000000000 --- a/docs/zh_cn/api_cn/one_shot_api.md +++ /dev/null @@ -1,155 +0,0 @@ -# OneShotNAS - -## OneShotSearch -paddleslim.nas.one_shot.OneShotSearch(model, eval_func, strategy='sa', search_steps=100)[代码]() - -: 从超级网络中搜索出一个最佳的子网络。 - -**参数:** - -- **model(fluid.dygraph.layer):** 通过在`OneShotSuperNet`前后添加若该模块构建的动态图模块。因为`OneShotSuperNet`是一个超网络,所以`model`也是一个超网络。换句话说,在`model`模块的子模块中,至少有一个是`OneShotSuperNet`的实例。该方法从`model`超网络中搜索得到一个最佳的子网络。超网络`model`需要先被训练,具体细节请参考[OneShotSuperNet]()。 - -- **eval_func:** 用于评估子网络性能的回调函数。该回调函数需要接受`model`为参数,并调用`model`的`forward`方法进行性能评估。 - -- **strategy(str):** 搜索策略的名称。默认为'sa', 当前仅支持'sa'. - -- **search_steps(int):** 搜索轮次数。默认为100。 - -**返回:** - -- **best_tokens:** 表示最佳子网络的编码信息(tokens)。 - -**示例代码:** - -请参考[one-shot NAS示例]() - - -## OneShotSuperNet - -用于`OneShot`搜索策略的超级网络的基类,所有超级网络的实现要继承该类。 - -paddleslim.nas.one_shot.OneShotSuperNet(name_scope) - -: 构造方法。 - -**参数:** - -- **name_scope:(str) **超级网络的命名空间。 - -**返回:** - -- **super_net:** 一个`OneShotSuperNet`实例。 - -init_tokens() - -: 获得当前超级网络的初始化子网络的编码,主要用于搜索。 - -**返回:** - -- **tokens(list):** 一个子网络的编码。 - -range_table() - -: 超级网络中各个子网络由一组整型数字编码表示,该方法返回编码每个位置的取值范围。 - -**返回:** - -- **range_table(tuple):** 子网络编码每一位的取值范围。`range_table`格式为`(min_values, max_values)`,其中,`min_values`为一个整型数组,表示每个编码位置可选取的最小值;`max_values`表示每个编码位置可选取的最大值。 - -_forward_impl(input, tokens) - -: 前向计算函数。`OneShotSuperNet`的子类需要实现该函数。 - -**参数:** - -- **input(Variable):** 超级网络的输入。 - -- **tokens(list):** 执行前向计算所用的子网络的编码。默认为`None`,即随机选取一个子网络执行前向。 - -**返回:** - -- **output(Variable):** 前向计算的输出 - -forward(self, input, tokens=None) - -: 执行前向计算。 - -**参数:** - -- **input(Variable):** 超级网络的输入。 - -- **tokens(list):** 执行前向计算所用的子网络的编码。默认为`None`,即随机选取一个子网络执行前向。 - -**返回:** - -- **output(Variable):** 前向计算的输出 - - -_random_tokens() - -: 随机选取一个子网络,并返回其编码。 - -**返回:** - -- **tokens(list):** 一个子网络的编码。 - -## SuperMnasnet - -在[Mnasnet](https://arxiv.org/abs/1807.11626)基础上修改得到的超级网络, 该类继承自`OneShotSuperNet`. - -paddleslim.nas.one_shot.SuperMnasnet(name_scope, input_channels=3, out_channels=1280, repeat_times=[6, 6, 6, 6, 6, 6], stride=[1, 1, 1, 1, 2, 1], channels=[16, 24, 40, 80, 96, 192, 320], use_auxhead=False) - -: 构造函数。 - -**参数:** - -- **name_scope(str):** 命名空间。 - -- **input_channels(str):** 当前超级网络的输入的特征图的通道数量。 - -- **out_channels(str):** 当前超级网络的输出的特征图的通道数量。 - -- **repeat_times(list):** 每种`block`重复的次数。 - -- **stride(list):** 一种`block`重复堆叠成`repeat_block`,`stride`表示每个`repeat_block`的下采样比例。 - -- **channels(list):** channels[i]和channels[i+1]分别表示第i个`repeat_block`的输入特征图的通道数和输出特征图的通道数。 - -- **use_auxhead(bool):** 是否使用辅助特征图。如果设置为`True`,则`SuperMnasnet`除了返回输出特征图,还还返回辅助特征图。默认为False. - -**返回:** - -- **instance(SuperMnasnet):** 一个`SuperMnasnet`实例 - -**示例:** -``` -import paddle -import paddle.fluid as fluid -class MNIST(fluid.dygraph.Layer): - def __init__(self): - super(MNIST, self).__init__() - self.arch = SuperMnasnet( - name_scope="super_net", input_channels=20, out_channels=20) - self.pool_2_shape = 50 * 13 * 13 - SIZE = 10 - scale = (2.0 / (self.pool_2_shape**2 * SIZE))**0.5 - self._fc = Linear( - self.pool_2_shape, - 10, - param_attr=fluid.param_attr.ParamAttr( - initializer=fluid.initializer.NormalInitializer( - loc=0.0, scale=scale)), - act="softmax") - - def forward(self, inputs, label=None, tokens=None): - - x = self.arch(inputs, tokens=tokens) - x = fluid.layers.reshape(x, shape=[-1, self.pool_2_shape]) - x = self._fc(x) - if label is not None: - acc = fluid.layers.accuracy(input=x, label=label) - return x, acc - else: - return x - -``` diff --git a/docs/zh_cn/api_cn/one_shot_api.rst b/docs/zh_cn/api_cn/one_shot_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..57ab5e5b936de5d800cb1dd9657a87d0b2fc2232 --- /dev/null +++ b/docs/zh_cn/api_cn/one_shot_api.rst @@ -0,0 +1,157 @@ +OneShotNAS +============= + +OneShotSearch +------------------ + +.. py:function:: paddleslim.nas.one_shot.OneShotSearch(model, eval_func, strategy='sa', search_steps=100) + +从超级网络中搜索出一个最佳的子网络。 + +**参数:** + +- **model(fluid.dygraph.layer):** 通过在 ``OneShotSuperNet`` 前后添加若该模块构建的动态图模块。因为 ``OneShotSuperNet`` 是一个超网络,所以 ``model`` 也是一个超网络。换句话说,在 ``model`` 模块的子模块中,至少有一个是 ``OneShotSuperNet`` 的实例。该方法从 ``model`` 超网络中搜索得到一个最佳的子网络。超网络 ``model`` 需要先被训练,具体细节请参考[OneShotSuperNet]()。 + +- **eval_func:** 用于评估子网络性能的回调函数。该回调函数需要接受 ``model`` 为参数,并调用 ``model`` 的 ``forward`` 方法进行性能评估。 + +- **strategy(str):** 搜索策略的名称。默认为 ``sa`` , 当前仅支持 ``sa`` . + +- **search_steps(int):** 搜索轮次数。默认为100。 + +**返回:** + +- **best_tokens:** 表示最佳子网络的编码信息(tokens)。 + +**示例代码:** + +请参考[one-shot NAS示例]() + + +OneShotSuperNet +----------------- + +.. py:class:: paddleslim.nas.one_shot.OneShotSuperNet(name_scope) + +用于`OneShot`搜索策略的超级网络的基类,所有超级网络的实现要继承该类。 + +**参数:** + +- **name_scope:(str) **超级网络的命名空间。 + +**返回:** + +- **super_net:** 一个`OneShotSuperNet`实例。 + + + .. py:method:: init_tokens() + + 获得当前超级网络的初始化子网络的编码,主要用于搜索。 + + **返回:** + + - **tokens(list):** 一个子网络的编码。 + + range_table() + + : 超级网络中各个子网络由一组整型数字编码表示,该方法返回编码每个位置的取值范围。 + + **返回:** + + - **range_table(tuple):** 子网络编码每一位的取值范围。 ``range_table`` 格式为 ``(min_values, max_values)`` ,其中, ``min_values`` 为一个整型数组,表示每个编码位置可选取的最小值; ``max_values`` 表示每个编码位置可选取的最大值。 + + .. py:method:: _forward_impl(input, tokens) + + 前向计算函数。 ``OneShotSuperNet`` 的子类需要实现该函数。 + + **参数:** + + - **input(Variable):** 超级网络的输入。 + + - **tokens(list):** 执行前向计算所用的子网络的编码。默认为 ``None`` ,即随机选取一个子网络执行前向。 + + **返回:** + + - **output(Variable):** 前向计算的输出 + + .. py:method:: forward(self, input, tokens=None) + + 执行前向计算。 + + **参数:** + + - **input(Variable):** 超级网络的输入。 + + - **tokens(list):** 执行前向计算所用的子网络的编码。默认为 ``None`` ,即随机选取一个子网络执行前向。 + + **返回:** + + - **output(Variable):** 前向计算的输出 + + + .. py:method:: _random_tokens() + + 随机选取一个子网络,并返回其编码。 + + **返回:** + + - **tokens(list):** 一个子网络的编码。 + +SuperMnasnet +-------------- + + +.. py:class:: paddleslim.nas.one_shot.SuperMnasnet(name_scope, input_channels=3, out_channels=1280, repeat_times=[6, 6, 6, 6, 6, 6], stride=[1, 1, 1, 1, 2, 1], channels=[16, 24, 40, 80, 96, 192, 320], use_auxhead=False) + +在 `Mnasnet `_ 基础上修改得到的超级网络, 该类继承自 ``OneShotSuperNet`` . + +**参数:** + +- **name_scope(str):** 命名空间。 + +- **input_channels(str):** 当前超级网络的输入的特征图的通道数量。 + +- **out_channels(str):** 当前超级网络的输出的特征图的通道数量。 + +- **repeat_times(list):** 每种 ``block`` 重复的次数。 + +- **stride(list):** 一种 ``block`` 重复堆叠成 ``repeat_block`` , ``stride`` 表示每个 ``repeat_block`` 的下采样比例。 + +- **channels(list):** ``channels[i]`` 和 ``channels[i+1]`` 分别表示第i个 ``repeat_block`` 的输入特征图的通道数和输出特征图的通道数。 + +- **use_auxhead(bool):** 是否使用辅助特征图。如果设置为 ``True`` ,则 ``SuperMnasnet`` 除了返回输出特征图,还还返回辅助特征图。默认为False. + +**返回:** + +- **instance(SuperMnasnet):** 一个 ``SuperMnasnet`` 实例 + +**示例:** +.. code-block:: python + + import paddle + import paddle.fluid as fluid + class MNIST(fluid.dygraph.Layer): + def __init__(self): + super(MNIST, self).__init__() + self.arch = SuperMnasnet( + name_scope="super_net", input_channels=20, out_channels=20) + self.pool_2_shape = 50 * 13 * 13 + SIZE = 10 + scale = (2.0 / (self.pool_2_shape**2 * SIZE))**0.5 + self._fc = Linear( + self.pool_2_shape, + 10, + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.NormalInitializer( + loc=0.0, scale=scale)), + act="softmax") + + def forward(self, inputs, label=None, tokens=None): + + x = self.arch(inputs, tokens=tokens) + x = fluid.layers.reshape(x, shape=[-1, self.pool_2_shape]) + x = self._fc(x) + if label is not None: + acc = fluid.layers.accuracy(input=x, label=label) + return x, acc + else: + return x diff --git a/docs/zh_cn/api_cn/prune_api.md b/docs/zh_cn/api_cn/prune_api.md deleted file mode 100644 index a46635d7198c06cc915e121d7edcbd29cdb020a6..0000000000000000000000000000000000000000 --- a/docs/zh_cn/api_cn/prune_api.md +++ /dev/null @@ -1,400 +0,0 @@ -# 卷积层通道剪裁 - -## Pruner -paddleslim.prune.Pruner(criterion="l1_norm")[源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/pruner.py#L28) - -: 对卷积网络的通道进行一次剪裁。剪裁一个卷积层的通道,是指剪裁该卷积层输出的通道。卷积层的权重形状为`[output_channel, input_channel, kernel_size, kernel_size]`,通过剪裁该权重的第一纬度达到剪裁输出通道数的目的。 - -**参数:** - -- **criterion** - 评估一个卷积层内通道重要性所参考的指标。目前仅支持`l1_norm`。默认为`l1_norm`。 - -**返回:** 一个Pruner类的实例 - -**示例代码:** - -```python -from paddleslim.prune import Pruner -pruner = Pruner() -``` - -paddleslim.prune.Pruner.prune(program, scope, params, ratios, place=None, lazy=False, only_graph=False, param_backup=False, param_shape_backup=False)[源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/pruner.py#L36) - -: 对目标网络的一组卷积层的权重进行裁剪。 - -**参数:** - -- **program(paddle.fluid.Program)** - 要裁剪的目标网络。更多关于Program的介绍请参考:[Program概念介绍](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Program_cn.html#program)。 - -- **scope(paddle.fluid.Scope)** - 要裁剪的权重所在的`scope`,Paddle中用`scope`实例存放模型参数和运行时变量的值。Scope中的参数值会被`inplace`的裁剪。更多介绍请参考[Scope概念介绍]() - -- **params(list)** - 需要被裁剪的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称: -```python -for block in program.blocks: - for param in block.all_parameters(): - print("param: {}; shape: {}".format(param.name, param.shape)) -``` - -- **ratios(list)** - 用于裁剪`params`的剪切率,类型为列表。该列表长度必须与`params`的长度一致。 - -- **place(paddle.fluid.Place)** - 待裁剪参数所在的设备位置,可以是`CUDAPlace`或`CPUPlace`。[Place概念介绍]() - -- **lazy(bool)** - `lazy`为True时,通过将指定通道的参数置零达到裁剪的目的,参数的`shape保持不变`;`lazy`为False时,直接将要裁的通道的参数删除,参数的`shape`会发生变化。 - -- **only_graph(bool)** - 是否只裁剪网络结构。在Paddle中,Program定义了网络结构,Scope存储参数的数值。一个Scope实例可以被多个Program使用,比如定义了训练网络的Program和定义了测试网络的Program是使用同一个Scope实例的。`only_graph`为True时,只对Program中定义的卷积的通道进行剪裁;`only_graph`为false时,Scope中卷积参数的数值也会被剪裁。默认为False。 - -- **param_backup(bool)** - 是否返回对参数值的备份。默认为False。 - -- **param_shape_backup(bool)** - 是否返回对参数`shape`的备份。默认为False。 - -**返回:** - -- **pruned_program(paddle.fluid.Program)** - 被裁剪后的Program。 - -- **param_backup(dict)** - 对参数数值的备份,用于恢复Scope中的参数数值。 - -- **param_shape_backup(dict)** - 对参数形状的备份。 - -**示例:** - -点击[AIStudio](https://aistudio.baidu.com/aistudio/projectDetail/200786)执行以下示例代码。 -```python - -import paddle.fluid as fluid -from paddle.fluid.param_attr import ParamAttr -from paddleslim.prune import Pruner - -def conv_bn_layer(input, - num_filters, - filter_size, - name, - stride=1, - groups=1, - act=None): - conv = fluid.layers.conv2d( - input=input, - num_filters=num_filters, - filter_size=filter_size, - stride=stride, - padding=(filter_size - 1) // 2, - groups=groups, - act=None, - param_attr=ParamAttr(name=name + "_weights"), - bias_attr=False, - name=name + "_out") - bn_name = name + "_bn" - return fluid.layers.batch_norm( - input=conv, - act=act, - name=bn_name + '_output', - param_attr=ParamAttr(name=bn_name + '_scale'), - bias_attr=ParamAttr(bn_name + '_offset'), - moving_mean_name=bn_name + '_mean', - moving_variance_name=bn_name + '_variance', ) - -main_program = fluid.Program() -startup_program = fluid.Program() -# X X O X O -# conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 -# | ^ | ^ -# |____________| |____________________| -# -# X: prune output channels -# O: prune input channels -with fluid.program_guard(main_program, startup_program): - input = fluid.data(name="image", shape=[None, 3, 16, 16]) - conv1 = conv_bn_layer(input, 8, 3, "conv1") - conv2 = conv_bn_layer(conv1, 8, 3, "conv2") - sum1 = conv1 + conv2 - conv3 = conv_bn_layer(sum1, 8, 3, "conv3") - conv4 = conv_bn_layer(conv3, 8, 3, "conv4") - sum2 = conv4 + sum1 - conv5 = conv_bn_layer(sum2, 8, 3, "conv5") - conv6 = conv_bn_layer(conv5, 8, 3, "conv6") - -place = fluid.CPUPlace() -exe = fluid.Executor(place) -scope = fluid.Scope() -exe.run(startup_program, scope=scope) -pruner = Pruner() -main_program, _, _ = pruner.prune( - main_program, - scope, - params=["conv4_weights"], - ratios=[0.5], - place=place, - lazy=False, - only_graph=False, - param_backup=False, - param_shape_backup=False) - -for param in main_program.global_block().all_parameters(): - if "weights" in param.name: - print("param name: {}; param shape: {}".format(param.name, param.shape)) - -``` - - ---- - -## sensitivity -paddleslim.prune.sensitivity(program, place, param_names, eval_func, sensitivities_file=None, pruned_ratios=None) [源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py#L34) - -: 计算网络中每个卷积层的敏感度。每个卷积层的敏感度信息统计方法为:依次剪掉当前卷积层不同比例的输出通道数,在测试集上计算剪裁后的精度损失。得到敏感度信息后,可以通过观察或其它方式确定每层卷积的剪裁率。 - -**参数:** - -- **program(paddle.fluid.Program)** - 待评估的目标网络。更多关于Program的介绍请参考:[Program概念介绍](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Program_cn.html#program)。 - -- **place(paddle.fluid.Place)** - 待分析的参数所在的设备位置,可以是`CUDAPlace`或`CPUPlace`。[Place概念介绍]() - -- **param_names(list)** - 待分析的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称: - -```python -for block in program.blocks: - for param in block.all_parameters(): - print("param: {}; shape: {}".format(param.name, param.shape)) -``` - -- **eval_func(function)** - 用于评估裁剪后模型效果的回调函数。该回调函数接受被裁剪后的`program`为参数,返回一个表示当前program的精度,用以计算当前裁剪带来的精度损失。 - -- **sensitivities_file(str)** - 保存敏感度信息的本地文件系统的文件。在敏感度计算过程中,会持续将新计算出的敏感度信息追加到该文件中。重启任务后,文件中已有敏感度信息不会被重复计算。该文件可以用`pickle`加载。 - -- **pruned_ratios(list)** - 计算卷积层敏感度信息时,依次剪掉的通道数比例。默认为[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]。 - -**返回:** - -- **sensitivities(dict)** - 存放敏感度信息的dict,其格式为: - -```python -{"weight_0": - {0.1: 0.22, - 0.2: 0.33 - }, - "weight_1": - {0.1: 0.21, - 0.2: 0.4 - } -} -``` - -其中,`weight_0`是卷积层参数的名称,sensitivities['weight_0']的`value`为剪裁比例,`value`为精度损失的比例。 - -**示例:** - -点击[AIStudio](https://aistudio.baidu.com/aistudio/projectdetail/201401)运行以下示例代码。 - -```python -import paddle -import numpy as np -import paddle.fluid as fluid -from paddle.fluid.param_attr import ParamAttr -from paddleslim.prune import sensitivity -import paddle.dataset.mnist as reader - -def conv_bn_layer(input, - num_filters, - filter_size, - name, - stride=1, - groups=1, - act=None): - conv = fluid.layers.conv2d( - input=input, - num_filters=num_filters, - filter_size=filter_size, - stride=stride, - padding=(filter_size - 1) // 2, - groups=groups, - act=None, - param_attr=ParamAttr(name=name + "_weights"), - bias_attr=False, - name=name + "_out") - bn_name = name + "_bn" - return fluid.layers.batch_norm( - input=conv, - act=act, - name=bn_name + '_output', - param_attr=ParamAttr(name=bn_name + '_scale'), - bias_attr=ParamAttr(bn_name + '_offset'), - moving_mean_name=bn_name + '_mean', - moving_variance_name=bn_name + '_variance', ) - -main_program = fluid.Program() -startup_program = fluid.Program() -# X X O X O -# conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 -# | ^ | ^ -# |____________| |____________________| -# -# X: prune output channels -# O: prune input channels -image_shape = [1,28,28] -with fluid.program_guard(main_program, startup_program): - image = fluid.data(name='image', shape=[None]+image_shape, dtype='float32') - label = fluid.data(name='label', shape=[None, 1], dtype='int64') - conv1 = conv_bn_layer(image, 8, 3, "conv1") - conv2 = conv_bn_layer(conv1, 8, 3, "conv2") - sum1 = conv1 + conv2 - conv3 = conv_bn_layer(sum1, 8, 3, "conv3") - conv4 = conv_bn_layer(conv3, 8, 3, "conv4") - sum2 = conv4 + sum1 - conv5 = conv_bn_layer(sum2, 8, 3, "conv5") - conv6 = conv_bn_layer(conv5, 8, 3, "conv6") - out = fluid.layers.fc(conv6, size=10, act="softmax") -# cost = fluid.layers.cross_entropy(input=out, label=label) -# avg_cost = fluid.layers.mean(x=cost) - acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) -# acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5) - - -place = fluid.CPUPlace() -exe = fluid.Executor(place) -exe.run(startup_program) - -val_reader = paddle.batch(reader.test(), batch_size=128) -val_feeder = feeder = fluid.DataFeeder( - [image, label], place, program=main_program) - -def eval_func(program): - - acc_top1_ns = [] - for data in val_reader(): - acc_top1_n = exe.run(program, - feed=val_feeder.feed(data), - fetch_list=[acc_top1.name]) - acc_top1_ns.append(np.mean(acc_top1_n)) - return np.mean(acc_top1_ns) -param_names = [] -for param in main_program.global_block().all_parameters(): - if "weights" in param.name: - param_names.append(param.name) -sensitivities = sensitivity(main_program, - place, - param_names, - eval_func, - sensitivities_file="./sensitive.data", - pruned_ratios=[0.1, 0.2, 0.3]) -print(sensitivities) - -``` - -## merge_sensitive -paddleslim.prune.merge_sensitive(sensitivities)[源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py#L161) - -: 合并多个敏感度信息。 - -参数: - -- **sensitivities(list | list)** - 待合并的敏感度信息,可以是字典的列表,或者是存放敏感度信息的文件的路径列表。 - -返回: - -- **sensitivities(dict)** - 合并后的敏感度信息。其格式为: - -```bash -{"weight_0": - {0.1: 0.22, - 0.2: 0.33 - }, - "weight_1": - {0.1: 0.21, - 0.2: 0.4 - } -} -``` - -其中,`weight_0`是卷积层参数的名称,sensitivities['weight_0']的`value`为剪裁比例,`value`为精度损失的比例。 - -示例: - -``` -from paddleslim.prune import merge_sensitive -sen0 = {"weight_0": - {0.1: 0.22, - 0.2: 0.33 - }, - "weight_1": - {0.1: 0.21, - 0.2: 0.4 - } -} -sen1 = {"weight_0": - {0.3: 0.41, - }, - "weight_2": - {0.1: 0.10, - 0.2: 0.35 - } -} -sensitivities = merge_sensitive([sen0, sen1]) -print(sensitivities) -``` - -## load_sensitivities -paddleslim.prune.load_sensitivities(sensitivities_file)[源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py#L184) - -: 从文件中加载敏感度信息。 - -参数: - -- **sensitivities_file(str)** - 存放敏感度信息的本地文件. - -返回: - -- **sensitivities(dict)** - 敏感度信息。 - -示例: - -``` -import pickle -from paddleslim.prune import load_sensitivities -sen = {"weight_0": - {0.1: 0.22, - 0.2: 0.33 - }, - "weight_1": - {0.1: 0.21, - 0.2: 0.4 - } -} -sensitivities_file = "sensitive_api_demo.data" -with open(sensitivities_file, 'w') as f: - pickle.dump(sen, f) -sensitivities = load_sensitivities(sensitivities_file) -print(sensitivities) -``` - -## get_ratios_by_loss -paddleslim.prune.get_ratios_by_loss(sensitivities, loss)[源代码](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py#L206) - -: 根据敏感度和精度损失阈值计算出一组剪切率。对于参数`w`, 其剪裁率为使精度损失低于`loss`的最大剪裁率。 - -参数: - -- **sensitivities(dict)** - 敏感度信息。 - -- **loss** - 精度损失阈值。 - -返回: - -- **ratios(dict)** - 一组剪切率。`key`是待剪裁参数的名称。`value`是对应参数的剪裁率。 - -示例: - -``` -from paddleslim.prune import get_ratios_by_loss -sen = {"weight_0": - {0.1: 0.22, - 0.2: 0.33 - }, - "weight_1": - {0.1: 0.21, - 0.2: 0.4 - } -} - -ratios = get_ratios_by_loss(sen, 0.3) -print(ratios) - -``` diff --git a/docs/zh_cn/api_cn/prune_api.rst b/docs/zh_cn/api_cn/prune_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..d38480d6055e52c86e3d20fa9d384040a7389856 --- /dev/null +++ b/docs/zh_cn/api_cn/prune_api.rst @@ -0,0 +1,421 @@ +卷积层通道剪裁 +================ + +Pruner +---------- + +.. py:class:: paddleslim.prune.Pruner(criterion="l1_norm") + +`源代码 `_ + +对卷积网络的通道进行一次剪裁。剪裁一个卷积层的通道,是指剪裁该卷积层输出的通道。卷积层的权重形状为 ``[output_channel, input_channel, kernel_size, kernel_size]`` ,通过剪裁该权重的第一纬度达到剪裁输出通道数的目的。 + +**参数:** + +- **criterion** - 评估一个卷积层内通道重要性所参考的指标。目前仅支持 ``l1_norm`` 。默认为 ``l1_norm`` 。 + +**返回:** 一个Pruner类的实例 + +**示例代码:** + +.. code-block:: python + + from paddleslim.prune import Pruner + pruner = Pruner() + +.. + + .. py:method:: paddleslim.prune.Pruner.prune(program, scope, params, ratios, place=None, lazy=False, only_graph=False, param_backup=False, param_shape_backup=False) + + 对目标网络的一组卷积层的权重进行裁剪。 + + **参数:** + + - **program(paddle.fluid.Program)** - 要裁剪的目标网络。更多关于Program的介绍请参考:`Program概念介绍 `_。 + + - **scope(paddle.fluid.Scope)** - 要裁剪的权重所在的 ``scope`` ,Paddle中用 ``scope`` 实例存放模型参数和运行时变量的值。Scope中的参数值会被 ``inplace`` 的裁剪。更多介绍请参考: `Scope概念介绍 <>`_ + + - **params(list)** - 需要被裁剪的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称: + + .. code-block:: python + + for block in program.blocks: + for param in block.all_parameters(): + print("param: {}; shape: {}".format(param.name, param.shape)) + + - **ratios(list)** - 用于裁剪 ``params`` 的剪切率,类型为列表。该列表长度必须与 ``params`` 的长度一致。 + + - **place(paddle.fluid.Place)** - 待裁剪参数所在的设备位置,可以是 ``CUDAPlace`` 或 ``CPUPlace`` 。[Place概念介绍]() + + - **lazy(bool)** - ``lazy`` 为True时,通过将指定通道的参数置零达到裁剪的目的,参数的 ``shape保持不变`` ; ``lazy`` 为False时,直接将要裁的通道的参数删除,参数的 ``shape`` 会发生变化。 + + - **only_graph(bool)** - 是否只裁剪网络结构。在Paddle中,Program定义了网络结构,Scope存储参数的数值。一个Scope实例可以被多个Program使用,比如定义了训练网络的Program和定义了测试网络的Program是使用同一个Scope实例的。 ``only_graph`` 为True时,只对Program中定义的卷积的通道进行剪裁; ``only_graph`` 为false时,Scope中卷积参数的数值也会被剪裁。默认为False。 + + - **param_backup(bool)** - 是否返回对参数值的备份。默认为False。 + + - **param_shape_backup(bool)** - 是否返回对参数 ``shape`` 的备份。默认为False。 + + **返回:** + + - **pruned_program(paddle.fluid.Program)** - 被裁剪后的Program。 + + - **param_backup(dict)** - 对参数数值的备份,用于恢复Scope中的参数数值。 + + - **param_shape_backup(dict)** - 对参数形状的备份。 + + **示例:** + + 点击 `AIStudio `_ 执行以下示例代码。 + + .. code-block:: python + + import paddle.fluid as fluid + from paddle.fluid.param_attr import ParamAttr + from paddleslim.prune import Pruner + + def conv_bn_layer(input, + num_filters, + filter_size, + name, + stride=1, + groups=1, + act=None): + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) // 2, + groups=groups, + act=None, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=False, + name=name + "_out") + bn_name = name + "_bn" + return fluid.layers.batch_norm( + input=conv, + act=act, + name=bn_name + '_output', + param_attr=ParamAttr(name=bn_name + '_scale'), + bias_attr=ParamAttr(bn_name + '_offset'), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance', ) + + main_program = fluid.Program() + startup_program = fluid.Program() + # X X O X O + # conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 + # | ^ | ^ + # |____________| |____________________| + # + # X: prune output channels + # O: prune input channels + with fluid.program_guard(main_program, startup_program): + input = fluid.data(name="image", shape=[None, 3, 16, 16]) + conv1 = conv_bn_layer(input, 8, 3, "conv1") + conv2 = conv_bn_layer(conv1, 8, 3, "conv2") + sum1 = conv1 + conv2 + conv3 = conv_bn_layer(sum1, 8, 3, "conv3") + conv4 = conv_bn_layer(conv3, 8, 3, "conv4") + sum2 = conv4 + sum1 + conv5 = conv_bn_layer(sum2, 8, 3, "conv5") + conv6 = conv_bn_layer(conv5, 8, 3, "conv6") + + place = fluid.CPUPlace() + exe = fluid.Executor(place) + scope = fluid.Scope() + exe.run(startup_program, scope=scope) + pruner = Pruner() + main_program, _, _ = pruner.prune( + main_program, + scope, + params=["conv4_weights"], + ratios=[0.5], + place=place, + lazy=False, + only_graph=False, + param_backup=False, + param_shape_backup=False) + + for param in main_program.global_block().all_parameters(): + if "weights" in param.name: + print("param name: {}; param shape: {}".format(param.name, param.shape)) + + +sensitivity +-------------- + +.. py:function:: paddleslim.prune.sensitivity(program, place, param_names, eval_func, sensitivities_file=None, pruned_ratios=None) + +`源代码 `_ + +计算网络中每个卷积层的敏感度。每个卷积层的敏感度信息统计方法为:依次剪掉当前卷积层不同比例的输出通道数,在测试集上计算剪裁后的精度损失。得到敏感度信息后,可以通过观察或其它方式确定每层卷积的剪裁率。 + +**参数:** + +- **program(paddle.fluid.Program)** - 待评估的目标网络。更多关于Program的介绍请参考:`Program概念介绍 `_。 + +- **place(paddle.fluid.Place)** - 待分析的参数所在的设备位置,可以是 ``CUDAPlace`` 或 ``CPUPlace`` 。[Place概念介绍]() + +- **param_names(list)** - 待分析的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称: + +.. code-block:: python + for block in program.blocks: + for param in block.all_parameters(): + print("param: {}; shape: {}".format(param.name, param.shape)) + +- **eval_func(function)** - 用于评估裁剪后模型效果的回调函数。该回调函数接受被裁剪后的 ``program`` 为参数,返回一个表示当前program的精度,用以计算当前裁剪带来的精度损失。 + +- **sensitivities_file(str)** - 保存敏感度信息的本地文件系统的文件。在敏感度计算过程中,会持续将新计算出的敏感度信息追加到该文件中。重启任务后,文件中已有敏感度信息不会被重复计算。该文件可以用 ``pickle`` 加载。 + +- **pruned_ratios(list)** - 计算卷积层敏感度信息时,依次剪掉的通道数比例。默认为 ``[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]`` 。 + +**返回:** + +- **sensitivities(dict)** - 存放敏感度信息的dict,其格式为: + +.. code-block:: python + + {"weight_0": + {0.1: 0.22, + 0.2: 0.33 + }, + "weight_1": + {0.1: 0.21, + 0.2: 0.4 + } + } + +其中, ``weight_0`` 是卷积层参数的名称, ``sensitivities['weight_0']`` 的 ``value`` 为剪裁比例, ``value`` 为精度损失的比例。 + +**示例:** + +点击 `AIStudio `_ 运行以下示例代码。 + +.. code-block:: python + + import paddle + import numpy as np + import paddle.fluid as fluid + from paddle.fluid.param_attr import ParamAttr + from paddleslim.prune import sensitivity + import paddle.dataset.mnist as reader + + def conv_bn_layer(input, + num_filters, + filter_size, + name, + stride=1, + groups=1, + act=None): + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) // 2, + groups=groups, + act=None, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=False, + name=name + "_out") + bn_name = name + "_bn" + return fluid.layers.batch_norm( + input=conv, + act=act, + name=bn_name + '_output', + param_attr=ParamAttr(name=bn_name + '_scale'), + bias_attr=ParamAttr(bn_name + '_offset'), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance', ) + + main_program = fluid.Program() + startup_program = fluid.Program() + # X X O X O + # conv1-->conv2-->sum1-->conv3-->conv4-->sum2-->conv5-->conv6 + # | ^ | ^ + # |____________| |____________________| + # + # X: prune output channels + # O: prune input channels + image_shape = [1,28,28] + with fluid.program_guard(main_program, startup_program): + image = fluid.data(name='image', shape=[None]+image_shape, dtype='float32') + label = fluid.data(name='label', shape=[None, 1], dtype='int64') + conv1 = conv_bn_layer(image, 8, 3, "conv1") + conv2 = conv_bn_layer(conv1, 8, 3, "conv2") + sum1 = conv1 + conv2 + conv3 = conv_bn_layer(sum1, 8, 3, "conv3") + conv4 = conv_bn_layer(conv3, 8, 3, "conv4") + sum2 = conv4 + sum1 + conv5 = conv_bn_layer(sum2, 8, 3, "conv5") + conv6 = conv_bn_layer(conv5, 8, 3, "conv6") + out = fluid.layers.fc(conv6, size=10, act="softmax") + # cost = fluid.layers.cross_entropy(input=out, label=label) + # avg_cost = fluid.layers.mean(x=cost) + acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) + # acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5) + + + place = fluid.CPUPlace() + exe = fluid.Executor(place) + exe.run(startup_program) + + val_reader = paddle.batch(reader.test(), batch_size=128) + val_feeder = feeder = fluid.DataFeeder( + [image, label], place, program=main_program) + + def eval_func(program): + + acc_top1_ns = [] + for data in val_reader(): + acc_top1_n = exe.run(program, + feed=val_feeder.feed(data), + fetch_list=[acc_top1.name]) + acc_top1_ns.append(np.mean(acc_top1_n)) + return np.mean(acc_top1_ns) + param_names = [] + for param in main_program.global_block().all_parameters(): + if "weights" in param.name: + param_names.append(param.name) + sensitivities = sensitivity(main_program, + place, + param_names, + eval_func, + sensitivities_file="./sensitive.data", + pruned_ratios=[0.1, 0.2, 0.3]) + print(sensitivities) + + +merge_sensitive +---------------- + +.. py:function:: paddleslim.prune.merge_sensitive(sensitivities) + +`源代码 `_ + +合并多个敏感度信息。 + +参数: + +- **sensitivities(list | list)** - 待合并的敏感度信息,可以是字典的列表,或者是存放敏感度信息的文件的路径列表。 + +返回: + +- **sensitivities(dict)** - 合并后的敏感度信息。其格式为: + +.. code-block:: bash + + {"weight_0": + {0.1: 0.22, + 0.2: 0.33 + }, + "weight_1": + {0.1: 0.21, + 0.2: 0.4 + } + } + + +其中, ``weight_0`` 是卷积层参数的名称, ``sensitivities['weight_0']`` 的 ``value`` 为剪裁比例, ``value`` 为精度损失的比例。 + +示例: + +.. code-block:: python + + from paddleslim.prune import merge_sensitive + sen0 = {"weight_0": + {0.1: 0.22, + 0.2: 0.33 + }, + "weight_1": + {0.1: 0.21, + 0.2: 0.4 + } + } + sen1 = {"weight_0": + {0.3: 0.41, + }, + "weight_2": + {0.1: 0.10, + 0.2: 0.35 + } + } + sensitivities = merge_sensitive([sen0, sen1]) + print(sensitivities) + + +load_sensitivities +--------------------- + +.. py:function:: paddleslim.prune.load_sensitivities(sensitivities_file) + +`源代码 `_ + +从文件中加载敏感度信息。 + +参数: + +- **sensitivities_file(str)** - 存放敏感度信息的本地文件. + +返回: + +- **sensitivities(dict)** - 敏感度信息。 + +示例: + +.. code-block:: python + + import pickle + from paddleslim.prune import load_sensitivities + sen = {"weight_0": + {0.1: 0.22, + 0.2: 0.33 + }, + "weight_1": + {0.1: 0.21, + 0.2: 0.4 + } + } + sensitivities_file = "sensitive_api_demo.data" + with open(sensitivities_file, 'w') as f: + pickle.dump(sen, f) + sensitivities = load_sensitivities(sensitivities_file) + print(sensitivities) + +get_ratios_by_loss +------------------- + +.. py:function:: paddleslim.prune.get_ratios_by_loss(sensitivities, loss) + +`源代码 `_ + +根据敏感度和精度损失阈值计算出一组剪切率。对于参数 ``w`` , 其剪裁率为使精度损失低于 ``loss`` 的最大剪裁率。 + +**参数:** + +- **sensitivities(dict)** - 敏感度信息。 + +- **loss** - 精度损失阈值。 + +**返回:** + +- **ratios(dict)** - 一组剪切率。 ``key`` 是待剪裁参数的名称。 ``value`` 是对应参数的剪裁率。 + +**示例:** + +.. code-block:: python + + from paddleslim.prune import get_ratios_by_loss + sen = {"weight_0": + {0.1: 0.22, + 0.2: 0.33 + }, + "weight_1": + {0.1: 0.21, + 0.2: 0.4 + } + } + + ratios = get_ratios_by_loss(sen, 0.3) + print(ratios) diff --git a/docs/zh_cn/api_cn/quantization_api.md b/docs/zh_cn/api_cn/quantization_api.md deleted file mode 100644 index 7150c9c783e889a75b3088861e3816c195a38378..0000000000000000000000000000000000000000 --- a/docs/zh_cn/api_cn/quantization_api.md +++ /dev/null @@ -1,269 +0,0 @@ -# 量化 - -## 量化配置 -通过字典配置量化参数 - -```python -TENSORRT_OP_TYPES = [ - 'mul', 'conv2d', 'pool2d', 'depthwise_conv2d', 'elementwise_add', - 'leaky_relu' -] -TRANSFORM_PASS_OP_TYPES = ['conv2d', 'depthwise_conv2d', 'mul'] - -QUANT_DEQUANT_PASS_OP_TYPES = [ - "pool2d", "elementwise_add", "concat", "softmax", "argmax", "transpose", - "equal", "gather", "greater_equal", "greater_than", "less_equal", - "less_than", "mean", "not_equal", "reshape", "reshape2", - "bilinear_interp", "nearest_interp", "trilinear_interp", "slice", - "squeeze", "elementwise_sub", "relu", "relu6", "leaky_relu", "tanh", "swish" - ] - -_quant_config_default = { - # weight quantize type, default is 'channel_wise_abs_max' - 'weight_quantize_type': 'channel_wise_abs_max', - # activation quantize type, default is 'moving_average_abs_max' - 'activation_quantize_type': 'moving_average_abs_max', - # weight quantize bit num, default is 8 - 'weight_bits': 8, - # activation quantize bit num, default is 8 - 'activation_bits': 8, - # ops of name_scope in not_quant_pattern list, will not be quantized - 'not_quant_pattern': ['skip_quant'], - # ops of type in quantize_op_types, will be quantized - 'quantize_op_types': ['conv2d', 'depthwise_conv2d', 'mul'], - # data type after quantization, such as 'uint8', 'int8', etc. default is 'int8' - 'dtype': 'int8', - # window size for 'range_abs_max' quantization. defaulf is 10000 - 'window_size': 10000, - # The decay coefficient of moving average, default is 0.9 - 'moving_rate': 0.9, - # if True, 'quantize_op_types' will be TENSORRT_OP_TYPES - 'for_tensorrt': False, - # if True, 'quantoze_op_types' will be TRANSFORM_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES - 'is_full_quantize': False -} -``` - -**参数:** - -- **weight_quantize_type(str)** - 参数量化方式。可选``'abs_max'``, ``'channel_wise_abs_max'``, ``'range_abs_max'``, ``'moving_average_abs_max'``。如果使用``TensorRT``加载量化后的模型来预测,请使用``'channel_wise_abs_max'``。 默认``'channel_wise_abs_max'``。 -- **activation_quantize_type(str)** - 激活量化方式,可选``'abs_max'``, ``'range_abs_max'``, ``'moving_average_abs_max'``。如果使用``TensorRT``加载量化后的模型来预测,请使用``'range_abs_max', 'moving_average_abs_max'``。,默认``'moving_average_abs_max'``。 -- **weight_bits(int)** - 参数量化bit数,默认8, 推荐设为8。 -- **activation_bits(int)** - 激活量化bit数,默认8, 推荐设为8。 -- **not_quant_pattern(str | list[str])** - 所有``name_scope``包含``'not_quant_pattern'``字符串的``op``,都不量化, 设置方式请参考[*fluid.name_scope*](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/name_scope_cn.html#name-scope)。 -- **quantize_op_types(list[str])** - 需要进行量化的``op``类型,目前支持``'conv2d', 'depthwise_conv2d', 'mul' ``。 -- **dtype(int8)** - 量化后的参数类型,默认 ``int8``, 目前仅支持``int8``。 -- **window_size(int)** - ``'range_abs_max'``量化方式的``window size``,默认10000。 -- **moving_rate(int)** - ``'moving_average_abs_max'``量化方式的衰减系数,默认 0.9。 -- **for_tensorrt(bool)** - 量化后的模型是否使用``TensorRT``进行预测。如果是的话,量化op类型为:``TENSORRT_OP_TYPES``。默认值为False. -- **is_full_quantize(bool)** - 是否量化所有可支持op类型。默认值为False. - -!!! note "注意事项" - -- 目前``Paddle-Lite``有int8 kernel来加速的op只有 ``['conv2d', 'depthwise_conv2d', 'mul']``, 其他op的int8 kernel将陆续支持。 - -## quant_aware -paddleslim.quant.quant_aware(program, place, config, scope=None, for_test=False)[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/quant/quanter.py) -: 在``program``中加入量化和反量化``op``, 用于量化训练。 - - -**参数:** - -* **program (fluid.Program)** - 传入训练或测试``program``。 -* **place(fluid.CPUPlace | fluid.CUDAPlace)** - 该参数表示``Executor``执行所在的设备。 -* **config(dict)** - 量化配置表。 -* **scope(fluid.Scope, optional)** - 传入用于存储``Variable``的``scope``,需要传入``program``所使用的``scope``,一般情况下,是[*fluid.global_scope()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html)。设置为``None``时将使用[*fluid.global_scope()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html),默认值为``None``。 -* **for_test(bool)** - 如果``program``参数是一个测试``program``,``for_test``应设为``True``,否则设为``False``。 - -**返回** - -含有量化和反量化``operator``的``program`` - -**返回类型** - -* 当``for_test=False``,返回类型为``fluid.CompiledProgram``, **注意,此返回值不能用于保存参数**。 -* 当``for_test=True``,返回类型为``fluid.Program``。 - -!!! note "注意事项" - -* 此接口会改变``program``结构,并且可能增加一些``persistable``的变量,所以加载模型参数时请注意和相应的``program``对应。 -* 此接口底层经历了``fluid.Program``-> ``fluid.framework.IrGraph``->``fluid.Program``的转变,在``fluid.framework.IrGraph``中没有``Parameter``的概念,``Variable``只有``persistable``和``not persistable``的区别,所以在保存和加载参数时,请使用``fluid.io.save_persistables``和``fluid.io.load_persistables``接口。 -* 由于此接口会根据``program``的结构和量化配置来对``program``添加op,所以``Paddle``中一些通过``fuse op``来加速训练的策略不能使用。已知以下策略在使用量化时必须设为``False``: ``fuse_all_reduce_ops, sync_batch_norm``。 -* 如果传入的``program``中存在和任何op都没有连接的``Variable``,则会在量化的过程中被优化掉。 - - - -## convert -paddleslim.quant.convert(program, place, config, scope=None, save_int8=False)[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/quant/quanter.py) - - -: 把训练好的量化``program``,转换为可用于保存``inference model``的``program``。 - -**参数:** - -- **program (fluid.Program)** - 传入测试``program``。 -- **place(fluid.CPUPlace | fluid.CUDAPlace)** - 该参数表示``Executor``执行所在的设备。 -- **config(dict)** - 量化配置表。 -- **scope(fluid.Scope)** - 传入用于存储``Variable``的``scope``,需要传入``program``所使用的``scope``,一般情况下,是[*fluid.global_scope()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html)。设置为``None``时将使用[*fluid.global_scope()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html),默认值为``None``。 -- **save_int8(bool)** - 是否需要返回参数为``int8``的``program``。该功能目前只能用于确认模型大小。默认值为``False``。 - -**返回** - -- **program (fluid.Program)** - freezed program,可用于保存inference model,参数为``float32``类型,但其数值范围可用int8表示。 -- **int8_program (fluid.Program)** - freezed program,可用于保存inference model,参数为``int8``类型。当``save_int8``为``False``时,不返回该值。 - -!!! note "注意事项" - -因为该接口会对``op``和``Variable``做相应的删除和修改,所以此接口只能在训练完成之后调用。如果想转化训练的中间模型,可加载相应的参数之后再使用此接口。 - -**代码示例** - -```python hl_lines="27 28" -#encoding=utf8 -import paddle.fluid as fluid -import paddleslim.quant as quant - - -train_program = fluid.Program() - -with fluid.program_guard(train_program): - image = fluid.data(name='x', shape=[None, 1, 28, 28]) - label = fluid.data(name='label', shape=[None, 1], dtype='int64') - conv = fluid.layers.conv2d(image, 32, 1) - feat = fluid.layers.fc(conv, 10, act='softmax') - cost = fluid.layers.cross_entropy(input=feat, label=label) - avg_cost = fluid.layers.mean(x=cost) - -use_gpu = True -place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace() -exe = fluid.Executor(place) -exe.run(fluid.default_startup_program()) -eval_program = train_program.clone(for_test=True) -#配置 -config = {'weight_quantize_type': 'abs_max', - 'activation_quantize_type': 'moving_average_abs_max'} -build_strategy = fluid.BuildStrategy() -exec_strategy = fluid.ExecutionStrategy() -#调用api -quant_train_program = quant.quant_aware(train_program, place, config, for_test=False) -quant_eval_program = quant.quant_aware(eval_program, place, config, for_test=True) -#关闭策略 -build_strategy.fuse_all_reduce_ops = False -build_strategy.sync_batch_norm = False -quant_train_program = quant_train_program.with_data_parallel( - loss_name=avg_cost.name, - build_strategy=build_strategy, - exec_strategy=exec_strategy) - -inference_prog = quant.convert(quant_eval_program, place, config) -``` - -更详细的用法请参考 量化训练demo。 - -## quant_post -paddleslim.quant.quant_post(executor, model_dir, quantize_model_path,sample_generator, model_filename=None, params_filename=None, batch_size=16,batch_nums=None, scope=None, algo='KL', quantizable_op_type=["conv2d", "depthwise_conv2d", "mul"], is_full_quantize=False, is_use_cache_file=False, cache_dir="./temp_post_training")[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/quant/quanter.py) - -: 对保存在``${model_dir}``下的模型进行量化,使用``sample_generator``的数据进行参数校正。 - -**参数:** - -- **executor (fluid.Executor)** - 执行模型的executor,可以在cpu或者gpu上执行。 -- **model_dir(str)** - 需要量化的模型所在的文件夹。 -- **quantize_model_path(str)** - 保存量化后的模型的路径 -- **sample_generator(python generator)** - 读取数据样本,每次返回一个样本。 -- **model_filename(str, optional)** - 模型文件名,如果需要量化的模型的参数存在一个文件中,则需要设置``model_filename``为模型文件的名称,否则设置为``None``即可。默认值是``None``。 -- **params_filename(str)** - 参数文件名,如果需要量化的模型的参数存在一个文件中,则需要设置``params_filename``为参数文件的名称,否则设置为``None``即可。默认值是``None``。 -- **batch_size(int)** - 每个batch的图片数量。默认值为16 。 -- **batch_nums(int, optional)** - 迭代次数。如果设置为``None``,则会一直运行到``sample_generator`` 迭代结束, 否则,迭代次数为``batch_nums``, 也就是说参与对``Scale``进行校正的样本个数为 ``'batch_nums' * 'batch_size' ``. -- **scope(fluid.Scope, optional)** - 用来获取和写入``Variable``, 如果设置为``None``,则使用[*fluid.global_scope()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html). 默认值是``None``. -- **algo(str)** - 量化时使用的算法名称,可为``'KL'``或者``'direct'``。该参数仅针对激活值的量化,因为参数值的量化使用的方式为``'channel_wise_abs_max'``. 当``algo`` 设置为``'direct'``时,使用校正数据的激活值的绝对值的最大值当作``Scale``值,当设置为``'KL'``时,则使用``KL``散度的方法来计算``Scale``值。默认值为``'KL'``。 -- **quantizable_op_type(list[str])** - 需要量化的``op``类型列表。默认值为``["conv2d", "depthwise_conv2d", "mul"]``。 -- **is_full_quantize(bool)** - 是否量化所有可支持的op类型。如果设置为False, 则按照 ``'quantizable_op_type'`` 的设置进行量化。 -- **is_use_cache_file(bool)** - 是否使用硬盘对中间结果进行存储。如果为False, 则将中间结果存储在内存中。 -- **cache_dir(str)** - 如果 ``'is_use_cache_file'``为True, 则将中间结果存储在此参数设置的路径下。 - -**返回** - -无。 - -!!! note "注意事项" - -- 因为该接口会收集校正数据的所有的激活值,当校正图片比较多时,请设置``'is_use_cache_file'``为True, 将中间结果存储在硬盘中。另外,``'KL'``散度的计算比较耗时。 -- 目前``Paddle-Lite``有int8 kernel来加速的op只有 ``['conv2d', 'depthwise_conv2d', 'mul']``, 其他op的int8 kernel将陆续支持。 - -**代码示例** - -> 注: 此示例不能直接运行,因为需要加载``${model_dir}``下的模型,所以不能直接运行。 - -```python hl_lines="9" -import paddle.fluid as fluid -import paddle.dataset.mnist as reader -from paddleslim.quant import quant_post -val_reader = reader.train() -use_gpu = True -place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace() - -exe = fluid.Executor(place) -quant_post( - executor=exe, - model_dir='./model_path', - quantize_model_path='./save_path', - sample_generator=val_reader, - model_filename='__model__', - params_filename='__params__', - batch_size=16, - batch_nums=10) -``` -更详细的用法请参考 离线量化demo。 - -## quant_embedding -paddleslim.quant.quant_embedding(program, place, config, scope=None)[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/quant/quant_embedding.py) -: 对``Embedding``参数进行量化。 - -**参数:** - -- **program(fluid.Program)** - 需要量化的program -- **scope(fluid.Scope, optional)** - 用来获取和写入``Variable``, 如果设置为``None``,则使用[*fluid.global_scope()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api_cn/executor_cn/global_scope_cn.html). -- **place(fluid.CPUPlace | fluid.CUDAPlace)** - 运行program的设备 -- **config(dict)** - 定义量化的配置。可以配置的参数有: - - ``'params_name'`` (str, required): 需要进行量化的参数名称,此参数必须设置。 - - ``'quantize_type'`` (str, optional): 量化的类型,目前支持的类型是``'abs_max'``, 待支持的类型有 ``'log', 'product_quantization'``。 默认值是``'abs_max'``. - - ``'quantize_bits'``(int, optional): 量化的``bit``数,目前支持的``bit``数为8。默认值是8. - - ``'dtype'``(str, optional): 量化之后的数据类型, 目前支持的是``'int8'``. 默认值是``int8``。 - - ``'threshold'``(float, optional): 量化之前将根据此阈值对需要量化的参数值进行``clip``. 如果不设置,则跳过``clip``过程直接量化。 - -**返回** - -量化之后的program - -**返回类型** - -``fluid.Program`` - -**代码示例** -```python hl_lines="22" -import paddle.fluid as fluid -import paddleslim.quant as quant - -train_program = fluid.Program() -with fluid.program_guard(train_program): - input_word = fluid.data(name="input_word", shape=[None, 1], dtype='int64') - input_emb = fluid.embedding( - input=input_word, - is_sparse=False, - size=[100, 128], - param_attr=fluid.ParamAttr(name='emb', - initializer=fluid.initializer.Uniform(-0.005, 0.005))) - -infer_program = train_program.clone(for_test=True) - -use_gpu = True -place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace() -exe = fluid.Executor(place) -exe.run(fluid.default_startup_program()) - -config = {'params_name': 'emb', 'quantize_type': 'abs_max'} -quant_program = quant.quant_embedding(infer_program, place, config) -``` - -更详细的用法请参考 Embedding量化demo。 diff --git a/docs/zh_cn/api_cn/quantization_api.rst b/docs/zh_cn/api_cn/quantization_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..e8080183b0c020888f3d75a5055e96cda1d73ee2 --- /dev/null +++ b/docs/zh_cn/api_cn/quantization_api.rst @@ -0,0 +1,294 @@ +量化 +==== + +量化配置 +--------------- +通过字典配置量化参数 + +.. code-block:: python + + + TENSORRT_OP_TYPES = [ + 'mul', 'conv2d', 'pool2d', 'depthwise_conv2d', 'elementwise_add', + 'leaky_relu' + ] + TRANSFORM_PASS_OP_TYPES = ['conv2d', 'depthwise_conv2d', 'mul'] + + QUANT_DEQUANT_PASS_OP_TYPES = [ + "pool2d", "elementwise_add", "concat", "softmax", "argmax", "transpose", + "equal", "gather", "greater_equal", "greater_than", "less_equal", + "less_than", "mean", "not_equal", "reshape", "reshape2", + "bilinear_interp", "nearest_interp", "trilinear_interp", "slice", + "squeeze", "elementwise_sub", "relu", "relu6", "leaky_relu", "tanh", "swish" + ] + + _quant_config_default = { + # weight quantize type, default is 'channel_wise_abs_max' + 'weight_quantize_type': 'channel_wise_abs_max', + # activation quantize type, default is 'moving_average_abs_max' + 'activation_quantize_type': 'moving_average_abs_max', + # weight quantize bit num, default is 8 + 'weight_bits': 8, + # activation quantize bit num, default is 8 + 'activation_bits': 8, + # ops of name_scope in not_quant_pattern list, will not be quantized + 'not_quant_pattern': ['skip_quant'], + # ops of type in quantize_op_types, will be quantized + 'quantize_op_types': ['conv2d', 'depthwise_conv2d', 'mul'], + # data type after quantization, such as 'uint8', 'int8', etc. default is 'int8' + 'dtype': 'int8', + # window size for 'range_abs_max' quantization. defaulf is 10000 + 'window_size': 10000, + # The decay coefficient of moving average, default is 0.9 + 'moving_rate': 0.9, + # if True, 'quantize_op_types' will be TENSORRT_OP_TYPES + 'for_tensorrt': False, + # if True, 'quantoze_op_types' will be TRANSFORM_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES + 'is_full_quantize': False + } + +**参数:** + +- **weight_quantize_type(str)** - 参数量化方式。可选 ``'abs_max'`` , ``'channel_wise_abs_max'`` , ``'range_abs_max'`` , ``'moving_average_abs_max'`` 。如果使用 ``TensorRT`` 加载量化后的模型来预测,请使用 ``'channel_wise_abs_max'`` 。 默认 ``'channel_wise_abs_max'`` 。 +- **activation_quantize_type(str)** - 激活量化方式,可选 ``'abs_max'`` , ``'range_abs_max'`` , ``'moving_average_abs_max'`` 。如果使用 ``TensorRT`` 加载量化后的模型来预测,请使用 ``'range_abs_max', 'moving_average_abs_max'`` 。,默认 ``'moving_average_abs_max'`` 。 +- **weight_bits(int)** - 参数量化bit数,默认8, 推荐设为8。 +- **activation_bits(int)** - 激活量化bit数,默认8, 推荐设为8。 +- **not_quant_pattern(str | list[str])** - 所有 ``name_scope`` 包含 ``'not_quant_pattern'`` 字符串的 ``op`` ,都不量化, 设置方式请参考 `fluid.name_scope `_ 。 +- **quantize_op_types(list[str])** - 需要进行量化的 ``op`` 类型,目前支持 ``'conv2d', 'depthwise_conv2d', 'mul'`` 。 +- **dtype(int8)** - 量化后的参数类型,默认 ``int8`` , 目前仅支持 ``int8`` 。 +- **window_size(int)** - ``'range_abs_max'`` 量化方式的 ``window size`` ,默认10000。 +- **moving_rate(int)** - ``'moving_average_abs_max'`` 量化方式的衰减系数,默认 0.9。 +- **for_tensorrt(bool)** - 量化后的模型是否使用 ``TensorRT`` 进行预测。如果是的话,量化op类型为: ``TENSORRT_OP_TYPES`` 。默认值为False. +- **is_full_quantize(bool)** - 是否量化所有可支持op类型。默认值为False. + +.. :note:: + + 目前 ``Paddle-Lite`` 有int8 kernel来加速的op只有 ``['conv2d', 'depthwise_conv2d', 'mul']``, 其他op的int8 kernel将陆续支持。 + + +quant_aware +------------ + +.. py:function:: paddleslim.quant.quant_aware(program, place, config, scope=None, for_test=False)[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/quant/quanter.py) + +在 ``program`` 中加入量化和反量化 ``op``, 用于量化训练。 + + +**参数:** + +- **program (fluid.Program)** - 传入训练或测试 ``program`` 。 +- **place(fluid.CPUPlace | fluid.CUDAPlace)** - 该参数表示 ``Executor`` 执行所在的设备。 +- **config(dict)** - 量化配置表。 +- **scope(fluid.Scope, optional)** - 传入用于存储 ``Variable`` 的 ``scope`` ,需要传入 ``program`` 所使用的 ``scope`` ,一般情况下,是 `fluid.global_scope() `_ 。设置为 ``None`` 时将使用 `fluid.global_scope() `_ ,默认值为 ``None`` 。 +- **for_test(bool)** - 如果 ``program`` 参数是一个测试 ``program`` , ``for_test`` 应设为 ``True`` ,否则设为 ``False`` 。 + +**返回** + +含有量化和反量化 ``operator`` 的 ``program`` 。 + +**返回类型** + +- 当 ``for_test=False`` ,返回类型为 ``fluid.CompiledProgram`` , **注意,此返回值不能用于保存参数** 。 +- 当 ``for_test=True`` ,返回类型为 ``fluid.Program`` 。 + +.. note:: + + - 此接口会改变 ``program`` 结构,并且可能增加一些``persistable``的变量,所以加载模型参数时请注意和相应的``program``对应。 + - 此接口底层经历了``fluid.Program``-> ``fluid.framework.IrGraph``->``fluid.Program``的转变,在``fluid.framework.IrGraph``中没有``Parameter``的概念,``Variable``只有``persistable``和``not persistable``的区别,所以在保存和加载参数时,请使用``fluid.io.save_persistables``和``fluid.io.load_persistables``接口。 + - 由于此接口会根据``program``的结构和量化配置来对``program``添加op,所以``Paddle``中一些通过``fuse op``来加速训练的策略不能使用。已知以下策略在使用量化时必须设为``False``: ``fuse_all_reduce_ops, sync_batch_norm``。 + - 如果传入的 ``program`` 中存在和任何op都没有连接的 ``Variable`` ,则会在量化的过程中被优化掉。 + + + +convert +--------- + +.. py:function:: paddleslim.quant.convert(program, place, config, scope=None, save_int8=False) + +`源代码 `_ + + +把训练好的量化 ``program`` ,转换为可用于保存 ``inference model`` 的 ``program`` 。 + +**参数:** + +- **program (fluid.Program)** - 传入测试``program``。 +- **place(fluid.CPUPlace | fluid.CUDAPlace)** - 该参数表示``Executor``执行所在的设备。 +- **config(dict)** - 量化配置表。 +- **scope(fluid.Scope)** - 传入用于存储``Variable``的``scope``,需要传入``program``所使用的``scope``,一般情况下,是 `fluid.global_scope() `_ 。设置为 ``None`` 时将使用 `fluid.global_scope() `_ ,默认值为 ``None`` 。 +- **save_int8(bool)** - 是否需要返回参数为 ``int8`` 的 ``program`` 。该功能目前只能用于确认模型大小。默认值为 ``False`` 。 + +**返回** + +- **program (fluid.Program)** - freezed program,可用于保存inference model,参数为``float32``类型,但其数值范围可用int8表示。 +- **int8_program (fluid.Program)** - freezed program,可用于保存inference model,参数为``int8``类型。当``save_int8``为``False``时,不返回该值。 + +.. note:: + + 因为该接口会对``op``和``Variable``做相应的删除和修改,所以此接口只能在训练完成之后调用。如果想转化训练的中间模型,可加载相应的参数之后再使用此接口。 + +**代码示例** + +.. code-block:: python + + #encoding=utf8 + import paddle.fluid as fluid + import paddleslim.quant as quant + + + train_program = fluid.Program() + + with fluid.program_guard(train_program): + image = fluid.data(name='x', shape=[None, 1, 28, 28]) + label = fluid.data(name='label', shape=[None, 1], dtype='int64') + conv = fluid.layers.conv2d(image, 32, 1) + feat = fluid.layers.fc(conv, 10, act='softmax') + cost = fluid.layers.cross_entropy(input=feat, label=label) + avg_cost = fluid.layers.mean(x=cost) + + use_gpu = True + place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace() + exe = fluid.Executor(place) + exe.run(fluid.default_startup_program()) + eval_program = train_program.clone(for_test=True) + #配置 + config = {'weight_quantize_type': 'abs_max', + 'activation_quantize_type': 'moving_average_abs_max'} + build_strategy = fluid.BuildStrategy() + exec_strategy = fluid.ExecutionStrategy() + #调用api + quant_train_program = quant.quant_aware(train_program, place, config, for_test=False) + quant_eval_program = quant.quant_aware(eval_program, place, config, for_test=True) + #关闭策略 + build_strategy.fuse_all_reduce_ops = False + build_strategy.sync_batch_norm = False + quant_train_program = quant_train_program.with_data_parallel( + loss_name=avg_cost.name, + build_strategy=build_strategy, + exec_strategy=exec_strategy) + + inference_prog = quant.convert(quant_eval_program, place, config) + +更详细的用法请参考 `量化训练demo `_ 。 + +quant_post +--------------- + +.. py:function:: paddleslim.quant.quant_post(executor, model_dir, quantize_model_path,sample_generator, model_filename=None, params_filename=None, batch_size=16,batch_nums=None, scope=None, algo='KL', quantizable_op_type=["conv2d", "depthwise_conv2d", "mul"], is_full_quantize=False, is_use_cache_file=False, cache_dir="./temp_post_training") + +`源代码 `_ + +对保存在 ``${model_dir}`` 下的模型进行量化,使用 ``sample_generator`` 的数据进行参数校正。 + +**参数:** + +- **executor (fluid.Executor)** - 执行模型的executor,可以在cpu或者gpu上执行。 +- **model_dir(str)** - 需要量化的模型所在的文件夹。 +- **quantize_model_path(str)** - 保存量化后的模型的路径 +- **sample_generator(python generator)** - 读取数据样本,每次返回一个样本。 +- **model_filename(str, optional)** - 模型文件名,如果需要量化的模型的参数存在一个文件中,则需要设置``model_filename``为模型文件的名称,否则设置为``None``即可。默认值是``None``。 +- **params_filename(str)** - 参数文件名,如果需要量化的模型的参数存在一个文件中,则需要设置``params_filename``为参数文件的名称,否则设置为``None``即可。默认值是``None``。 +- **batch_size(int)** - 每个batch的图片数量。默认值为16 。 +- **batch_nums(int, optional)** - 迭代次数。如果设置为``None``,则会一直运行到``sample_generator`` 迭代结束, 否则,迭代次数为``batch_nums``, 也就是说参与对 ``Scale`` 进行校正的样本个数为 ``'batch_nums' * 'batch_size'`` . +- **scope(fluid.Scope, optional)** - 用来获取和写入 ``Variable`` , 如果设置为 ``None`` ,则使用 `fluid.global_scope() `_ . 默认值是``None``. +- **algo(str)** - 量化时使用的算法名称,可为 ``'KL'`` 或者 ``'direct'`` 。该参数仅针对激活值的量化,因为参数值的量化使用的方式为 ``'channel_wise_abs_max'`` . 当 ``algo`` 设置为 ``'direct'`` 时,使用校正数据的激活值的绝对值的最大值当作 ``Scale`` 值,当设置为 ``'KL'`` 时,则使用KL散度的方法来计算 ``Scale`` 值。默认值为 ``'KL'`` 。 +- **quantizable_op_type(list[str])** - 需要量化的 ``op`` 类型列表。默认值为 ``["conv2d", "depthwise_conv2d", "mul"]`` 。 +- **is_full_quantize(bool)** - 是否量化所有可支持的op类型。如果设置为False, 则按照 ``'quantizable_op_type'`` 的设置进行量化。 +- **is_use_cache_file(bool)** - 是否使用硬盘对中间结果进行存储。如果为False, 则将中间结果存储在内存中。 +- **cache_dir(str)** - 如果 ``'is_use_cache_file'`` 为True, 则将中间结果存储在此参数设置的路径下。 + +**返回** + +无。 + +.. note:: + + - 因为该接口会收集校正数据的所有的激活值,当校正图片比较多时,请设置``'is_use_cache_file'``为True, 将中间结果存储在硬盘中。另外,``'KL'``散度的计算比较耗时。 + - 目前``Paddle-Lite``有int8 kernel来加速的op只有 ``['conv2d', 'depthwise_conv2d', 'mul']``, 其他op的int8 kernel将陆续支持。 + +**代码示例** + +.. warning:: + + 此示例不能直接运行,因为需要加载``${model_dir}``下的模型,所以不能直接运行。 + +.. code-block:: python + + import paddle.fluid as fluid + import paddle.dataset.mnist as reader + from paddleslim.quant import quant_post + val_reader = reader.train() + use_gpu = True + place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace() + + exe = fluid.Executor(place) + quant_post( + executor=exe, + model_dir='./model_path', + quantize_model_path='./save_path', + sample_generator=val_reader, + model_filename='__model__', + params_filename='__params__', + batch_size=16, + batch_nums=10) + + +更详细的用法请参考 `离线量化demo `_ 。 + +quant_embedding +------------------- + +.. py:function:: paddleslim.quant.quant_embedding(program, place, config, scope=None) + +`源代码 `_ + +对 ``Embedding`` 参数进行量化。 + +**参数:** + +- **program(fluid.Program)** - 需要量化的program +- **scope(fluid.Scope, optional)** - 用来获取和写入``Variable``, 如果设置为``None``,则使用 `fluid.global_scope() `_ . +- **place(fluid.CPUPlace | fluid.CUDAPlace)** - 运行program的设备 +- **config(dict)** - 定义量化的配置。可以配置的参数有: + - ``'params_name'`` (str, required): 需要进行量化的参数名称,此参数必须设置。 + - ``'quantize_type'`` (str, optional): 量化的类型,目前支持的类型是 ``'abs_max'``, 待支持的类型有 ``'log', 'product_quantization'`` 。 默认值是``'abs_max'`` . + - ``'quantize_bits'`` (int, optional): 量化的 ``bit`` 数,目前支持的 ``bit`` 数为8。默认值是8. + - ``'dtype'`` (str, optional): 量化之后的数据类型, 目前支持的是 ``'int8'``. 默认值是 ``int8`` 。 + - ``'threshold'`` (float, optional): 量化之前将根据此阈值对需要量化的参数值进行 ``clip``. 如果不设置,则跳过 ``clip`` 过程直接量化。 + +**返回** + +量化之后的program + +**返回类型** + +fluid.Program + +**代码示例** + +.. code-block:: python + + import paddle.fluid as fluid + import paddleslim.quant as quant + + train_program = fluid.Program() + with fluid.program_guard(train_program): + input_word = fluid.data(name="input_word", shape=[None, 1], dtype='int64') + input_emb = fluid.embedding( + input=input_word, + is_sparse=False, + size=[100, 128], + param_attr=fluid.ParamAttr(name='emb', + initializer=fluid.initializer.Uniform(-0.005, 0.005))) + + infer_program = train_program.clone(for_test=True) + + use_gpu = True + place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace() + exe = fluid.Executor(place) + exe.run(fluid.default_startup_program()) + + config = {'params_name': 'emb', 'quantize_type': 'abs_max'} + quant_program = quant.quant_embedding(infer_program, place, config) + +更详细的用法请参考 `Embedding量化demo `_ diff --git a/docs/zh_cn/api_cn/single_distiller_api.md b/docs/zh_cn/api_cn/single_distiller_api.md deleted file mode 100644 index e3df7c86bbeb31b01e6dddd0f4a4f8654172c79e..0000000000000000000000000000000000000000 --- a/docs/zh_cn/api_cn/single_distiller_api.md +++ /dev/null @@ -1,218 +0,0 @@ -# 简单蒸馏 - -## merge -paddleslim.dist.merge(teacher_program, student_program, data_name_map, place, scope=fluid.global_scope(), name_prefix='teacher_') [[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L19) - -: merge将teacher_program融合到student_program中。在融合的program中,可以为其中合适的teacher特征图和student特征图添加蒸馏损失函数,从而达到用teacher模型的暗知识(Dark Knowledge)指导student模型学习的目的。 - -**参数:** - -- **teacher_program**(Program)-定义了teacher模型的 [*paddle program*](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Program_cn.html#program) -- **student_program**(Program)-定义了student模型的 [*paddle program*](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Program_cn.html#program) -- **data_name_map**(dict)-teacher输入接口名与student输入接口名的映射,其中dict的 *key* 为teacher的输入名,*value* 为student的输入名 -- **place**(fluid.CPUPlace()|fluid.CUDAPlace(N))-该参数表示程序运行在何种设备上,这里的N为GPU对应的ID -- **scope**(Scope)-该参数表示程序使用的变量作用域,如果不指定将使用默认的全局作用域。默认值:[*fluid.global_scope()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/global_scope_cn.html#global-scope) -- **name_prefix**(str)-merge操作将统一为teacher的[*Variables*](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.3/api_guides/low_level/program.html#variable)添加的名称前缀name_prefix。默认值:'teacher_' - -**返回:** 无 - -!!! note "Note" - *data_name_map* 是 **teacher_var name到student_var name的映射**,如果写反可能无法正确进行merge - - -**使用示例:** - -```python hl_lines="17 18" -import paddle.fluid as fluid -import paddleslim.dist as dist -student_program = fluid.Program() -with fluid.program_guard(student_program): - x = fluid.layers.data(name='x', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(x, 32, 1) - out = fluid.layers.conv2d(conv, 64, 3, padding=1) -teacher_program = fluid.Program() -with fluid.program_guard(teacher_program): - y = fluid.layers.data(name='y', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(y, 32, 1) - conv = fluid.layers.conv2d(conv, 32, 3, padding=1) - out = fluid.layers.conv2d(conv, 64, 3, padding=1) -data_name_map = {'y':'x'} -USE_GPU = False -place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() -dist.merge(teacher_program, student_program, - data_name_map, place) -``` - - -## fsp_loss -paddleslim.dist.fsp_loss(teacher_var1_name, teacher_var2_name, student_var1_name, student_var2_name, program=fluid.default_main_program()) [[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L90) - -: fsp_loss为program内的teacher var和student var添加fsp loss,出自论文[<\>](http://openaccess.thecvf.com/content_cvpr_2017/papers/Yim_A_Gift_From_CVPR_2017_paper.pdf) - -**参数:** - -- **teacher_var1_name**(str): teacher_var1的名称. 对应的variable是一个形为`[batch_size, x_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64 -- **teacher_var2_name**(str): teacher_var2的名称. 对应的variable是一个形为`[batch_size, y_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64。只有y_channel可以与teacher_var1的x_channel不同,其他维度必须与teacher_var1相同 -- **student_var1_name**(str): student_var1的名称. 对应的variable需与teacher_var1尺寸保持一致,是一个形为`[batch_size, x_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64 -- **student_var2_name**(str): student_var2的名称. 对应的variable需与teacher_var2尺寸保持一致,是一个形为`[batch_size, y_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64。只有y_channel可以与student_var1的x_channel不同,其他维度必须与student_var1相同 -- **program**(Program): 用于蒸馏训练的fluid program。默认值:[*fluid.default_main_program()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.3/api_cn/fluid_cn.html#default-main-program) - -**返回:** 由teacher_var1, teacher_var2, student_var1, student_var2组合得到的fsp_loss - -**使用示例:** - -```python hl_lines="19 20" -import paddle.fluid as fluid -import paddleslim.dist as dist -student_program = fluid.Program() -with fluid.program_guard(student_program): - x = fluid.layers.data(name='x', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(x, 32, 1, name='s1') - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') -teacher_program = fluid.Program() -with fluid.program_guard(teacher_program): - y = fluid.layers.data(name='y', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(y, 32, 1, name='t1') - conv = fluid.layers.conv2d(conv, 32, 3, padding=1) - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') -data_name_map = {'y':'x'} -USE_GPU = False -place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() -dist.merge(teacher_program, student_program, data_name_map, place) -with fluid.program_guard(student_program): - distillation_loss = dist.fsp_loss('teacher_t1.tmp_1', 'teacher_t2.tmp_1', - 's1.tmp_1', 's2.tmp_1', student_program) -``` - - - -## l2_loss -paddleslim.dist.l2_loss(teacher_var_name, student_var_name, program=fluid.default_main_program())[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L118) - -: l2_loss为program内的teacher var和student var添加l2 loss - -**参数:** - -- **teacher_var_name**(str): teacher_var的名称. -- **student_var_name**(str): student_var的名称. -- **program**(Program): 用于蒸馏训练的fluid program。默认值:[*fluid.default_main_program()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.3/api_cn/fluid_cn.html#default-main-program) - -**返回:** 由teacher_var, student_var组合得到的l2_loss - -**使用示例:** - -```python hl_lines="19 20" -import paddle.fluid as fluid -import paddleslim.dist as dist -student_program = fluid.Program() -with fluid.program_guard(student_program): - x = fluid.layers.data(name='x', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(x, 32, 1, name='s1') - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') -teacher_program = fluid.Program() -with fluid.program_guard(teacher_program): - y = fluid.layers.data(name='y', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(y, 32, 1, name='t1') - conv = fluid.layers.conv2d(conv, 32, 3, padding=1) - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') -data_name_map = {'y':'x'} -USE_GPU = False -place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() -dist.merge(teacher_program, student_program, data_name_map, place) -with fluid.program_guard(student_program): - distillation_loss = dist.l2_loss('teacher_t2.tmp_1', 's2.tmp_1', - student_program) -``` - - - -## soft_label_loss -paddleslim.dist.soft_label_loss(teacher_var_name, student_var_name, program=fluid.default_main_program(), teacher_temperature=1., student_temperature=1.)[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L136) - -: soft_label_loss为program内的teacher var和student var添加soft label loss,出自论文[<\>](https://arxiv.org/pdf/1503.02531.pdf) - -**参数:** - -- **teacher_var_name**(str): teacher_var的名称. -- **student_var_name**(str): student_var的名称. -- **program**(Program): 用于蒸馏训练的fluid program。默认值:[*fluid.default_main_program()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.3/api_cn/fluid_cn.html#default-main-program) -- **teacher_temperature**(float): 对teacher_var进行soft操作的温度值,温度值越大得到的特征图越平滑 -- **student_temperature**(float): 对student_var进行soft操作的温度值,温度值越大得到的特征图越平滑 - -**返回:** 由teacher_var, student_var组合得到的soft_label_loss - -**使用示例:** - -```python hl_lines="19 20" -import paddle.fluid as fluid -import paddleslim.dist as dist -student_program = fluid.Program() -with fluid.program_guard(student_program): - x = fluid.layers.data(name='x', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(x, 32, 1, name='s1') - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') -teacher_program = fluid.Program() -with fluid.program_guard(teacher_program): - y = fluid.layers.data(name='y', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(y, 32, 1, name='t1') - conv = fluid.layers.conv2d(conv, 32, 3, padding=1) - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') -data_name_map = {'y':'x'} -USE_GPU = False -place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() -dist.merge(teacher_program, student_program, data_name_map, place) -with fluid.program_guard(student_program): - distillation_loss = dist.soft_label_loss('teacher_t2.tmp_1', - 's2.tmp_1', student_program, 1., 1.) -``` - - - -## loss -paddleslim.dist.loss(loss_func, program=fluid.default_main_program(), **kwargs) [[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L165) - -: loss函数支持对任意多对teacher_var和student_var使用自定义损失函数 - -**参数:** - -- **loss_func**(python function): 自定义的损失函数,输入为teacher var和student var,输出为自定义的loss -- **program**(Program): 用于蒸馏训练的fluid program。默认值:[*fluid.default_main_program()*](https://www.paddlepaddle.org.cn/documentation/docs/zh/1.3/api_cn/fluid_cn.html#default-main-program) -- **\**kwargs**: loss_func输入名与对应variable名称 - -**返回**:自定义的损失函数loss - -**使用示例:** - -```python hl_lines="24 25" -import paddle.fluid as fluid -import paddleslim.dist as dist -student_program = fluid.Program() -with fluid.program_guard(student_program): - x = fluid.layers.data(name='x', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(x, 32, 1, name='s1') - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') -teacher_program = fluid.Program() -with fluid.program_guard(teacher_program): - y = fluid.layers.data(name='y', shape=[1, 28, 28]) - conv = fluid.layers.conv2d(y, 32, 1, name='t1') - conv = fluid.layers.conv2d(conv, 32, 3, padding=1) - out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') -data_name_map = {'y':'x'} -USE_GPU = False -place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() -dist.merge(teacher_program, student_program, data_name_map, place) -def adaptation_loss(t_var, s_var): - teacher_channel = t_var.shape[1] - s_hint = fluid.layers.conv2d(s_var, teacher_channel, 1) - hint_loss = fluid.layers.reduce_mean(fluid.layers.square(s_hint - t_var)) - return hint_loss -with fluid.program_guard(student_program): - distillation_loss = dist.loss(adaptation_loss, student_program, - t_var='teacher_t2.tmp_1', s_var='s2.tmp_1') -``` - -!!! note "注意事项" - 在添加蒸馏loss时会引入新的variable,需要注意新引入的variable不要与student variables命名冲突。这里建议两种用法(两种方法任选其一即可): - - 1. 建议与student_program使用同一个命名空间,以避免一些未指定名称的variables(例如tmp_0, tmp_1...)多次定义为同一名称出现命名冲突 - 2. 建议在添加蒸馏loss时指定一个命名空间前缀,具体用法请参考Paddle官方文档[*fluid.name_scope*](https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/name_scope_cn.html#name-scope) diff --git a/docs/zh_cn/api_cn/single_distiller_api.rst b/docs/zh_cn/api_cn/single_distiller_api.rst new file mode 100644 index 0000000000000000000000000000000000000000..9c9dc8a2e15beb7928c8ebe47b3bc06f166af3dc --- /dev/null +++ b/docs/zh_cn/api_cn/single_distiller_api.rst @@ -0,0 +1,232 @@ +简单蒸馏 +========= + +merge +--------- + +.. py:function:: paddleslim.dist.merge(teacher_program, student_program, data_name_map, place, scope=fluid.global_scope(), name_prefix='teacher_') + +`源代码 `_ + +merge将teacher_program融合到student_program中。在融合的program中,可以为其中合适的teacher特征图和student特征图添加蒸馏损失函数,从而达到用teacher模型的暗知识(Dark Knowledge)指导student模型学习的目的。 + +**参数:** + +- **teacher_program** (Program)-定义了teacher模型的 `paddle program `_ +- **student_program** (Program)-定义了student模型的 `paddle program `_ +- **data_name_map** (dict)-teacher输入接口名与student输入接口名的映射,其中dict的 *key* 为teacher的输入名,*value* 为student的输入名 +- **place** (fluid.CPUPlace()|fluid.CUDAPlace(N))-该参数表示程序运行在何种设备上,这里的N为GPU对应的ID +- **scope** (Scope)-该参数表示程序使用的变量作用域,如果不指定将使用默认的全局作用域。默认值: `fluid.global_scope() `_ +- **name_prefix** (str)-merge操作将统一为teacher的 `Variables `_ 添加的名称前缀name_prefix。默认值:'teacher_' + +**返回:** 无 + +.. note:: + + *data_name_map* 是 **teacher_var name到student_var name的映射** ,如果写反可能无法正确进行merge + + +**使用示例:** + +.. code-block:: python + + import paddle.fluid as fluid + import paddleslim.dist as dist + student_program = fluid.Program() + with fluid.program_guard(student_program): + x = fluid.layers.data(name='x', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(x, 32, 1) + out = fluid.layers.conv2d(conv, 64, 3, padding=1) + teacher_program = fluid.Program() + with fluid.program_guard(teacher_program): + y = fluid.layers.data(name='y', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(y, 32, 1) + conv = fluid.layers.conv2d(conv, 32, 3, padding=1) + out = fluid.layers.conv2d(conv, 64, 3, padding=1) + data_name_map = {'y':'x'} + USE_GPU = False + place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() + dist.merge(teacher_program, student_program, + data_name_map, place) + + +fsp_loss +--------- + +.. py:function:: paddleslim.dist.fsp_loss(teacher_var1_name, teacher_var2_name, student_var1_name, student_var2_name, program=fluid.default_main_program()) + +`源代码 `_ + +fsp_loss为program内的teacher var和student var添加fsp loss,出自论文 `A Gift from Knowledge Distillation: Fast Optimization, Network Minimization and Transfer Learning `_ + +**参数:** + +- **teacher_var1_name** (str): teacher_var1的名称. 对应的variable是一个形为`[batch_size, x_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64 +- **teacher_var2_name** (str): teacher_var2的名称. 对应的variable是一个形为`[batch_size, y_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64。只有y_channel可以与teacher_var1的x_channel不同,其他维度必须与teacher_var1相同 +- **student_var1_name** (str): student_var1的名称. 对应的variable需与teacher_var1尺寸保持一致,是一个形为`[batch_size, x_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64 +- **student_var2_name** (str): student_var2的名称. 对应的variable需与teacher_var2尺寸保持一致,是一个形为`[batch_size, y_channel, height, width]`的4-D特征图Tensor,数据类型为float32或float64。只有y_channel可以与student_var1的x_channel不同,其他维度必须与student_var1相同 +- **program** (Program): 用于蒸馏训练的fluid program。默认值: `fluid.default_main_program() `_ + +**返回:** 由teacher_var1, teacher_var2, student_var1, student_var2组合得到的fsp_loss + +**使用示例:** + +.. code-block:: python + import paddle.fluid as fluid + import paddleslim.dist as dist + student_program = fluid.Program() + with fluid.program_guard(student_program): + x = fluid.layers.data(name='x', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(x, 32, 1, name='s1') + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') + teacher_program = fluid.Program() + with fluid.program_guard(teacher_program): + y = fluid.layers.data(name='y', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(y, 32, 1, name='t1') + conv = fluid.layers.conv2d(conv, 32, 3, padding=1) + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') + data_name_map = {'y':'x'} + USE_GPU = False + place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() + dist.merge(teacher_program, student_program, data_name_map, place) + with fluid.program_guard(student_program): + distillation_loss = dist.fsp_loss('teacher_t1.tmp_1', 'teacher_t2.tmp_1', + 's1.tmp_1', 's2.tmp_1', student_program) + + + +l2_loss +------------ + +.. py:function:: paddleslim.dist.l2_loss(teacher_var_name, student_var_name, program=fluid.default_main_program())[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L118) + +: l2_loss为program内的teacher var和student var添加l2 loss + +**参数:** + +- **teacher_var_name** (str): teacher_var的名称. +- **student_var_name** (str): student_var的名称. +- **program** (Program): 用于蒸馏训练的fluid program。默认值: `fluid.default_main_program() `_ + +**返回:** 由teacher_var, student_var组合得到的l2_loss + +**使用示例:** + +.. code-block:: python + import paddle.fluid as fluid + import paddleslim.dist as dist + student_program = fluid.Program() + with fluid.program_guard(student_program): + x = fluid.layers.data(name='x', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(x, 32, 1, name='s1') + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') + teacher_program = fluid.Program() + with fluid.program_guard(teacher_program): + y = fluid.layers.data(name='y', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(y, 32, 1, name='t1') + conv = fluid.layers.conv2d(conv, 32, 3, padding=1) + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') + data_name_map = {'y':'x'} + USE_GPU = False + place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() + dist.merge(teacher_program, student_program, data_name_map, place) + with fluid.program_guard(student_program): + distillation_loss = dist.l2_loss('teacher_t2.tmp_1', 's2.tmp_1', + student_program) + + + +soft_label_loss +------------------- + +.. py:function:: paddleslim.dist.soft_label_loss(teacher_var_name, student_var_name, program=fluid.default_main_program(), teacher_temperature=1., student_temperature=1.)[[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L136) + +soft_label_loss为program内的teacher var和student var添加soft label loss,出自论文 `Distilling the Knowledge in a Neural Network `_ + +**参数:** + +- **teacher_var_name** (str): teacher_var的名称. +- **student_var_name** (str): student_var的名称. +- **program** (Program): 用于蒸馏训练的fluid program。默认值: `fluid.default_main_program() `_ +- **teacher_temperature** (float): 对teacher_var进行soft操作的温度值,温度值越大得到的特征图越平滑 +- **student_temperature** (float): 对student_var进行soft操作的温度值,温度值越大得到的特征图越平滑 + +**返回:** 由teacher_var, student_var组合得到的soft_label_loss + +**使用示例:** + +.. code-block:: python + import paddle.fluid as fluid + import paddleslim.dist as dist + student_program = fluid.Program() + with fluid.program_guard(student_program): + x = fluid.layers.data(name='x', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(x, 32, 1, name='s1') + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') + teacher_program = fluid.Program() + with fluid.program_guard(teacher_program): + y = fluid.layers.data(name='y', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(y, 32, 1, name='t1') + conv = fluid.layers.conv2d(conv, 32, 3, padding=1) + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') + data_name_map = {'y':'x'} + USE_GPU = False + place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() + dist.merge(teacher_program, student_program, data_name_map, place) + with fluid.program_guard(student_program): + distillation_loss = dist.soft_label_loss('teacher_t2.tmp_1', + 's2.tmp_1', student_program, 1., 1.) + + + +loss +-------- + +.. py:function:: paddleslim.dist.loss(loss_func, program=fluid.default_main_program(), **kwargs) [[源代码]](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L165) + +: loss函数支持对任意多对teacher_var和student_var使用自定义损失函数 + +**参数:** + +- **loss_func**( python function): 自定义的损失函数,输入为teacher var和student var,输出为自定义的loss +- **program** (Program): 用于蒸馏训练的fluid program。默认值: `fluid.default_main_program() `_ +- **\**kwargs** : loss_func输入名与对应variable名称 + +**返回** :自定义的损失函数loss + +**使用示例:** + +.. code-block:: python + import paddle.fluid as fluid + import paddleslim.dist as dist + student_program = fluid.Program() + with fluid.program_guard(student_program): + x = fluid.layers.data(name='x', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(x, 32, 1, name='s1') + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='s2') + teacher_program = fluid.Program() + with fluid.program_guard(teacher_program): + y = fluid.layers.data(name='y', shape=[1, 28, 28]) + conv = fluid.layers.conv2d(y, 32, 1, name='t1') + conv = fluid.layers.conv2d(conv, 32, 3, padding=1) + out = fluid.layers.conv2d(conv, 64, 3, padding=1, name='t2') + data_name_map = {'y':'x'} + USE_GPU = False + place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() + dist.merge(teacher_program, student_program, data_name_map, place) + def adaptation_loss(t_var, s_var): + teacher_channel = t_var.shape[1] + s_hint = fluid.layers.conv2d(s_var, teacher_channel, 1) + hint_loss = fluid.layers.reduce_mean(fluid.layers.square(s_hint - t_var)) + return hint_loss + with fluid.program_guard(student_program): + distillation_loss = dist.loss(adaptation_loss, student_program, + t_var='teacher_t2.tmp_1', s_var='s2.tmp_1') + +.. note:: + + 在添加蒸馏loss时会引入新的variable,需要注意新引入的variable不要与student variables命名冲突。这里建议两种用法(两种方法任选其一即可): + + 1. 建议与student_program使用同一个命名空间,以避免一些未指定名称的variables(例如tmp_0, tmp_1...)多次定义为同一名称出现命名冲突 + + 2. 建议在添加蒸馏loss时指定一个命名空间前缀,具体用法请参考Paddle官方文档 `fluid.name_scope `_ diff --git a/docs/zh_cn/quick_start/index.rst b/docs/zh_cn/quick_start/index.rst index 231119b10f97d7729437dcab1b31d9ff37fe8d3b..8886d49613436ec00c2c89667e2da4b20e3fb967 100644 --- a/docs/zh_cn/quick_start/index.rst +++ b/docs/zh_cn/quick_start/index.rst @@ -3,9 +3,11 @@ ======== .. toctree:: - :maxdepth: 2 - :caption: Contents: + :maxdepth: 1 pruning_tutorial.md + distillation_tutorial.md + quant_aware_tutorial.md + quant_post_tutorial.md nas_tutorial.md