未验证 提交 6ac0720c 编写于 作者: W whs 提交者: GitHub

Format zh_cn API docs (#94)

上级 7c9fa0dd
# PaddleSlim文档构建与发布教程 # 文档构建与发布教程
## 1. 文档构成 ## 1. 文档构成
...@@ -70,7 +70,16 @@ make html ...@@ -70,7 +70,16 @@ make html
以上命令生成`html`文件到路径`./build/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` 进入路径`PaddleSlim/docs/en`
...@@ -123,6 +132,6 @@ git commit -m "update pages" ...@@ -123,6 +132,6 @@ git commit -m "update pages"
git push origin gh-pages git push origin gh-pages
``` ```
# 4. 其它 ## 4. 其它
英文API文档格式请参考:https://wanghaoshuang.github.io/PaddleSlim/api_en/paddleslim.analysis.html 英文API文档格式请参考:https://wanghaoshuang.github.io/PaddleSlim/api_en/paddleslim.analysis.html
...@@ -17,3 +17,4 @@ help: ...@@ -17,3 +17,4 @@ help:
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile %: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
rm -rf $(BUILDDIR)/html/index.html
...@@ -17,3 +17,4 @@ help: ...@@ -17,3 +17,4 @@ help:
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile %: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
rm -rf $(BUILDDIR)/$@/index_en.html
# 模型分析
## 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** - 目标网络的预估延时。
模型分析
=======
FLOPs
-----
.. py:function:: 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值。
**示例:**
.. 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)
`源代码 <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)** - 整个网络的参数数量。
**示例:**
.. 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=",")
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/analysis/latency.py>`_
基于硬件延时表的模型延时评估器。
**参数:**
- **table_file(str)** - 所使用的延时评估表的绝对路径。关于演示评估表格式请参考:PaddleSlim硬件延时评估表格式
- **delimiter(str)** - 在硬件延时评估表中,操作信息之前所使用的分割符,默认为英文字符逗号。
**返回值:**
- **Evaluator** - 硬件延时评估器的实例。
.. py:method:: latency(graph)
获得指定网络的预估延时。
**参数:**
- **graph(Program)** - 待预估的目标网络。
**返回值:**
- **latency** - 目标网络的预估延时。
...@@ -9,12 +9,12 @@ API文档 ...@@ -9,12 +9,12 @@ API文档
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
analysis_api.md analysis_api.rst
nas_api.md nas_api.rst
one_shot_api.md one_shot_api.rst
pantheon_api.md pantheon_api.md
prune_api.md prune_api.rst
quantization_api.md quantization_api.rst
single_distiller_api.md single_distiller_api.rst
search_space.md search_space.md
table_latency.md table_latency.md
# SA-NAS SA-NAS
========
## 搜索空间参数的配置 搜索空间参数的配置
通过参数配置搜索空间。更多搜索空间的使用可以参考[search_space](../search_space.md) ----------------------
通过参数配置搜索空间。更多搜索空间的使用可以参考: [search_space](../search_space.md)
**参数:** **参数:**
- **input_size(int|None)**:- `input_size`表示输入feature map的大小。`input_size``output_size`用来计算整个模型结构中下采样次数。 - **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的数量。 - **output_size(int|None)**:- ``output_size`` 表示输出feature map的大小。 ``input_size`` 和 ``output_size`` 用来计算整个模型结构中下采样次数。
- **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`三种配置是无效的。
- **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
------
## 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)
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) `源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/nas/sa_nas.py#L36>`_
: SANAS(Simulated Annealing Neural Architecture Search)是基于模拟退火算法进行模型结构搜索的算法,一般用于离散搜索任务。
SANAS(Simulated Annealing Neural Architecture Search)是基于模拟退火算法进行模型结构搜索的算法,一般用于离散搜索任务。
**参数:** **参数:**
- **configs(list<tuple>)** - 搜索空间配置列表,格式是`[(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) - **configs(list<tuple>)** - 搜索空间配置列表,格式是 ``[(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)。 - **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。 - **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。 - **reduce_rate(float)** - 基于模拟退火进行搜索的衰减率。详细的退火率设置可以参考下面的Note。默认:0.85。
- **init_tokens(list|None)** - 初始化token,若init_tokens为空,则SA算法随机生成初始化tokens。默认:None。 - **init_tokens(list|None)** - 初始化token,若init_tokens为空,则SA算法随机生成初始化tokens。默认:None。
- **search_steps(int)** - 搜索过程迭代的次数。默认:300。 - **search_steps(int)** - 搜索过程迭代的次数。默认:300。
- **save_checkpoint(str|None)** - 保存checkpoint的文件目录,如果设置为None的话则不保存checkpoint。默认:`./nas_checkpoint` - **save_checkpoint(str|None)** - 保存checkpoint的文件目录,如果设置为None的话则不保存checkpoint。默认: ``./nas_checkpoint``
- **load_checkpoint(str|None)** - 加载checkpoint的文件目录,如果设置为None的话则不加载checkpoint。默认:None。 - **load_checkpoint(str|None)** - 加载checkpoint的文件目录,如果设置为None的话则不加载checkpoint。默认:None。
- **is_server(bool)** - 当前实例是否要启动一个server。默认:True。 - **is_server(bool)** - 当前实例是否要启动一个server。默认:True。
...@@ -31,102 +42,119 @@ paddleslim.nas.SANAS(configs, server_addr=("", 8881), init_temperature=None, red ...@@ -31,102 +42,119 @@ paddleslim.nas.SANAS(configs, server_addr=("", 8881), init_temperature=None, red
一个SANAS类的实例 一个SANAS类的实例
**示例代码:** **示例代码:**
```python
from paddleslim.nas import SANAS
config = [('MobileNetV2Space')]
sanas = SANAS(configs=config)
```
!!! note "Note"
- 初始化温度和退火率的意义: <br>
- SA算法内部会保存一个基础token(初始化token可以自己传入也可以随机生成)和基础score(初始化score为-1),下一个token会在当前SA算法保存的token的基础上产生。在SA的搜索过程中,如果本轮的token训练得到的score大于SA算法中保存的score,则本轮的token一定会被SA算法接收保存为下一轮token产生的基础token。<br>
- 初始温度越高表示SA算法当前处的阶段越不稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越大。<br>
- 初始温度越低表示SA算法当前处的阶段越稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越小。<br>
- 退火率越大,表示SA算法收敛的越慢,即SA算法越慢到稳定阶段。<br>
- 退火率越低,表示SA算法收敛的越快,即SA算法越快到稳定阶段。<br>
- 初始化温度和退火率的设置: <br>
- 如果原本就有一个较好的初始化token,想要基于这个较好的token来进行搜索的话,SA算法可以处于一个较为稳定的状态进行搜索r这种情况下初始温度可以设置的低一些,例如设置为1.0,退火率设置的大一些,例如设置为0.85。如果想要基于这个较好的token利用贪心算法进行搜索,即只有当本轮token训练得到的score大于SA算法中保存的score,SA算法才接收本轮token,则退火率可设置为一个极小的数字,例如设置为0.85 ** 10。<br>
- 初始化token如果是随机生成的话,代表初始化token是一个比较差的token,SA算法可以处于一种不稳定的阶段进行搜索,尽可能的随机探索所有可能得token,从而找到一个较好的token。初始温度可以设置的高一些,例如设置为1000,退火率相对设置的小一些。
.. code-block:: python
paddleslim.nas.SANAS.next_archs() from paddleslim.nas import SANAS
: 获取下一组模型结构。 config = [('MobileNetV2Space')]
sanas = SANAS(configs=config)
**返回:** .. note::
返回模型结构实例的列表,形式为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)
: 把当前模型结构的得分情况回传。
**参数:** - SA算法内部会保存一个基础token(初始化token可以自己传入也可以随机生成)和基础score(初始化score为-1),下一个token会在当前SA算法保存的token的基础上产生。在SA的搜索过程中,如果本轮的token训练得到的score大于SA算法中保存的score,则本轮的token一定会被SA算法接收保存为下一轮token产生的基础token。
- **score<float>:** - 当前模型的得分,分数越大越好 - 初始温度越高表示SA算法当前处的阶段越不稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越大
**返回:** - 初始温度越低表示SA算法当前处的阶段越稳定,本轮的token训练得到的score小于SA算法中保存的score的话,本轮的token和score被SA算法接收的可能性越小。
模型结构更新成功或者失败,成功则返回`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))
```
- 退火率越大,表示SA算法收敛的越慢,即SA算法越慢到稳定阶段。
paddleslim.nas.SANAS.tokens2arch(tokens) - 退火率越低,表示SA算法收敛的越快,即SA算法越快到稳定阶段。
: 通过一组tokens得到实际的模型结构,一般用来把搜索到最优的token转换为模型结构用来做最后的训练。tokens的形式是一个列表,tokens映射到搜索空间转换成相应的网络结构,一组tokens对应唯一的一个网络结构。
**参数:** - 初始化温度和退火率的设置:
- **tokens(list):** - 一组tokens。tokens的长度和范取决于搜索空间。
**返回:** - 如果原本就有一个较好的初始化token,想要基于这个较好的token来进行搜索的话,SA算法可以处于一个较为稳定的状态进行搜索r这种情况下初始温度可以设置的低一些,例如设置为1.0,退火率设置的大一些,例如设置为0.85。如果想要基于这个较好的token利用贪心算法进行搜索,即只有当本轮token训练得到的score大于SA算法中保存的score,SA算法才接收本轮token,则退火率可设置为一个极小的数字,例如设置为0.85 ** 10。
根据传入的token得到一个模型结构实例。
**示例代码:** - 初始化token如果是随机生成的话,代表初始化token是一个比较差的token,SA算法可以处于一种不稳定的阶段进行搜索,尽可能的随机探索所有可能得token,从而找到一个较好的token。初始温度可以设置的高一些,例如设置为1000,退火率相对设置的小一些。
```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 .. py:method:: next_archs()
from paddleslim.nas import SANAS
config = [('MobileNetV2Space')] 获取下一组模型结构。
sanas = SANAS(configs=config)
print(sanas.current_info()) **返回:**
``` 返回模型结构实例的列表,形式为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<float>:** - 当前模型的得分,分数越大越好。
**返回:**
模型结构更新成功或者失败,成功则返回 ``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())
# 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<int>):** 一个子网络的编码。
range_table()
: 超级网络中各个子网络由一组整型数字编码表示,该方法返回编码每个位置的取值范围。
**返回:**
- **range_table(tuple):** 子网络编码每一位的取值范围。`range_table`格式为`(min_values, max_values)`,其中,`min_values`为一个整型数组,表示每个编码位置可选取的最小值;`max_values`表示每个编码位置可选取的最大值。
_forward_impl(input, tokens)
: 前向计算函数。`OneShotSuperNet`的子类需要实现该函数。
**参数:**
- **input(Variable):** 超级网络的输入。
- **tokens(list<int>):** 执行前向计算所用的子网络的编码。默认为`None`,即随机选取一个子网络执行前向。
**返回:**
- **output(Variable):** 前向计算的输出
forward(self, input, tokens=None)
: 执行前向计算。
**参数:**
- **input(Variable):** 超级网络的输入。
- **tokens(list<int>):** 执行前向计算所用的子网络的编码。默认为`None`,即随机选取一个子网络执行前向。
**返回:**
- **output(Variable):** 前向计算的输出
_random_tokens()
: 随机选取一个子网络,并返回其编码。
**返回:**
- **tokens(list<int>):** 一个子网络的编码。
## 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
```
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<int>):** 一个子网络的编码。
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<int>):** 执行前向计算所用的子网络的编码。默认为 ``None`` ,即随机选取一个子网络执行前向。
**返回:**
- **output(Variable):** 前向计算的输出
.. py:method:: forward(self, input, tokens=None)
执行前向计算。
**参数:**
- **input(Variable):** 超级网络的输入。
- **tokens(list<int>):** 执行前向计算所用的子网络的编码。默认为 ``None`` ,即随机选取一个子网络执行前向。
**返回:**
- **output(Variable):** 前向计算的输出
.. py:method:: _random_tokens()
随机选取一个子网络,并返回其编码。
**返回:**
- **tokens(list<int>):** 一个子网络的编码。
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 <https://arxiv.org/abs/1807.11626>`_ 基础上修改得到的超级网络, 该类继承自 ``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
# 卷积层通道剪裁
## 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<str>)** - 需要被裁剪的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称:
```python
for block in program.blocks:
for param in block.all_parameters():
print("param: {}; shape: {}".format(param.name, param.shape))
```
- **ratios(list<float>)** - 用于裁剪`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<str>)** - 待分析的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称:
```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<float>)** - 计算卷积层敏感度信息时,依次剪掉的通道数比例。默认为[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<dict> | list<str>)** - 待合并的敏感度信息,可以是字典的列表,或者是存放敏感度信息的文件的路径列表。
返回:
- **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)
```
卷积层通道剪裁
================
Pruner
----------
.. py:class:: 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类的实例
**示例代码:**
.. 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概念介绍 <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<str>)** - 需要被裁剪的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称:
.. code-block:: python
for block in program.blocks:
for param in block.all_parameters():
print("param: {}; shape: {}".format(param.name, param.shape))
- **ratios(list<float>)** - 用于裁剪 ``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>`_ 执行以下示例代码。
.. 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)
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py>`_
计算网络中每个卷积层的敏感度。每个卷积层的敏感度信息统计方法为:依次剪掉当前卷积层不同比例的输出通道数,在测试集上计算剪裁后的精度损失。得到敏感度信息后,可以通过观察或其它方式确定每层卷积的剪裁率。
**参数:**
- **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<str>)** - 待分析的卷积层的参数的名称列表。可以通过以下方式查看模型中所有参数的名称:
.. 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<float>)** - 计算卷积层敏感度信息时,依次剪掉的通道数比例。默认为 ``[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 <https://aistudio.baidu.com/aistudio/projectdetail/201401>`_ 运行以下示例代码。
.. 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)
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py>`_
合并多个敏感度信息。
参数:
- **sensitivities(list<dict> | list<str>)** - 待合并的敏感度信息,可以是字典的列表,或者是存放敏感度信息的文件的路径列表。
返回:
- **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)
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py#L184>`_
从文件中加载敏感度信息。
参数:
- **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)
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py>`_
根据敏感度和精度损失阈值计算出一组剪切率。对于参数 ``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)
# 量化
## 量化配置
通过字典配置量化参数
```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)
```
更详细的用法请参考 <a href='https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/quant/quant_aware'>量化训练demo</a>
## 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)
```
更详细的用法请参考 <a href='https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/quant/quant_post'>离线量化demo</a>
## 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)
```
更详细的用法请参考 <a href='https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/quant/quant_embedding'>Embedding量化demo</a>
量化
====
量化配置
---------------
通过字典配置量化参数
.. 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 <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
------------
.. 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() <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
---------
.. py:function:: 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``做相应的删除和修改,所以此接口只能在训练完成之后调用。如果想转化训练的中间模型,可加载相应的参数之后再使用此接口。
**代码示例**
.. 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 <https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/quant/quant_aware>`_ 。
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")
`源代码 <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将陆续支持。
**代码示例**
.. 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 <https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/quant/quant_post>`_ 。
quant_embedding
-------------------
.. py:function:: 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
**代码示例**
.. 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 <https://github.com/PaddlePaddle/PaddleSlim/tree/develop/demo/quant/quant_embedding'>`_
# 简单蒸馏
## 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,出自论文[<<A Gift from Knowledge Distillation: Fast Optimization, Network Minimization and Transfer Learning\>\>](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,出自论文[<<Distilling the Knowledge in a Neural Network\>\>](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)
简单蒸馏
=========
merge
---------
.. py:function:: 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::
*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())
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/dist/single_distiller.py#L90>`_
fsp_loss为program内的teacher var和student var添加fsp loss,出自论文 `A Gift from Knowledge Distillation: Fast Optimization, Network Minimization and Transfer Learning <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
**使用示例:**
.. 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() <https://www.paddlepaddle.org.cn/documentation/docs/zh/1.3/api_cn/fluid_cn.html#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 <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
**使用示例:**
.. 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() <https://www.paddlepaddle.org.cn/documentation/docs/zh/1.3/api_cn/fluid_cn.html#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 <https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/name_scope_cn.html#name-scope>`_
...@@ -3,9 +3,11 @@ ...@@ -3,9 +3,11 @@
======== ========
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 1
:caption: Contents:
pruning_tutorial.md pruning_tutorial.md
distillation_tutorial.md
quant_aware_tutorial.md
quant_post_tutorial.md
nas_tutorial.md nas_tutorial.md
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册