Skip to content

Commit 1492712

Browse files
authored
prune the optimizer in dygraph mode (#784)
* prune the optimizer in dygraph mode * set opt when initializing pruner * tests passed locally * update Chinese docs and tutorials * refine docs style * avoid ambiguation in docs
1 parent e3587f5 commit 1492712

File tree

13 files changed

+211
-80
lines changed

13 files changed

+211
-80
lines changed

docs/zh_cn/api_cn/dygraph/pruners/fpgm_filter_pruner.rst

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
FPGMFilterPruner
22
==================
33

4-
.. py:class:: paddleslim.FPGMFilterPruner(model, inputs, sen_file=None)
4+
.. py:class:: paddleslim.FPGMFilterPruner(model, inputs, sen_file=None, opt=None)
55
66
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/release/2.0.0/paddleslim/dygraph/prune/fpgm_pruner.py>`_
77

8-
用于剪裁卷积层输出通道的的剪裁器。该剪裁器按论文 `Filter Pruning via Geometric Median for Deep Convolutional Neural Networks Acceleration <https://arxiv.org/abs/1811.00250>_` 中的统计方法对单个卷积层内的 ``Filters`` 的重要性进行排序,并按指定比例剪裁掉相对不重要的 ``Filters`` 。对 ``Filters`` 的剪裁等价于剪裁卷积层的输出通道数。
8+
用于剪裁卷积层输出通道的的剪裁器。该剪裁器按论文 `Filter Pruning via Geometric Median for Deep Convolutional Neural Networks Acceleration <https://arxiv.org/abs/1811.00250>`_ 中的统计方法对单个卷积层内的 ``Filters`` 的重要性进行排序,并按指定比例剪裁掉相对不重要的 ``Filters`` 。对 ``Filters`` 的剪裁等价于剪裁卷积层的输出通道数。
99

1010
**参数:**
1111

@@ -15,17 +15,40 @@ FPGMFilterPruner
1515

1616
- **sen_file(str)** - 存储敏感度信息的文件,需要指定为绝对路径。在调用当前剪裁器的 ``sensitive`` 方法时,敏感度信息会以增量的形式追加到文件 ``sen_file`` 中。如果用户不需要敏感度剪裁策略,可以将该选项设置为 ``None`` 。默认为None。
1717

18+
- **opt(paddle.optimizer.Optimizer)** - 动态图模型训练时用到的优化器。传入该参数是为了解决上述 ``model(paddle.nn.Layer)`` 不含有优化器,导致不能剪裁到优化器参数(例如 ``Momentum`` 中的 ``velocity`` )的问题。是否传入 ``optimizer`` 参数的逻辑为:若已经初始化了 ``optimizer`` 对象,则传入;否则,在调用 ``pruner.prune_vars()`` 之后初始化 ``optimize`` 。默认为None。
19+
1820
**返回:** 一个剪裁器实例。
1921

20-
**示例代码**
22+
**示例代码1**
2123

2224
.. code-block:: python
2325
26+
import paddle
2427
from paddle.vision.models import mobilenet_v1
2528
from paddleslim import FPGMFilterPruner
26-
net = mobilenet_v1(pretrained=False)
29+
net = mobilenet_v1(pretrained=False)
2730
pruner = FPGMFilterPruner(net, [1, 3, 224, 224])
31+
pruner.prune_var("conv2d_26.w_0", [0], pruned_ratio=0.5)
32+
optimizer = paddle.optimizer.Momentum(
33+
learning_rate=0.1,
34+
parameters=net.parameters())
2835
..
36+
37+
**示例代码2:**
38+
39+
.. code-block:: python
40+
41+
import paddle
42+
from paddle.vision.models import mobilenet_v1
43+
from paddleslim import FPGMFilterPruner
44+
net = mobilenet_v1(pretrained=False)
45+
optimizer = paddle.optimizer.Momentum(
46+
learning_rate=0.1,
47+
parameters=net.parameters())
48+
pruner = FPGMFilterPruner(net, [1, 3, 224, 224], opt=optimizer)
49+
..
50+
51+
**注意:** 上述两段代码展示了如何在 ``pruner`` 中是否调用 ``optimizer`` ,在示例代码1中,初始化 ``optimizer`` 时传入的 ``parameters`` 为剪裁后的 ``net.parameters()`` ,故无需在初始化 ``pruner`` 时传入 ``optimizer`` ;反之在示例代码2中, ``optimizer`` 中的 ``parameter`` 为剪裁前,故需要传入给 ``pruner`` 一并剪裁 ``optimizer`` 中的相关参数。
2952

3053
.. py:method:: prune_var(var_name, pruned_dims, pruned_ratio, apply="impretive")
3154
@@ -124,6 +147,7 @@ FPGMFilterPruner
124147
0.2: 0.4
125148
}
126149
}
150+
..
127151
128152
其中,``weight_0`` 是卷积层权重变量的名称, ``sensitivities['weight_0']`` 是一个字典, key是用 ``float`` 类型数值表示的剪裁率,value是对应剪裁率下整个模型的精度损失比例。
129153

@@ -169,7 +193,7 @@ FPGMFilterPruner
169193
pruner = FPGMFilterPruner(net, [1, 3, 224, 224])
170194
sen = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle")
171195
print(f"sen: {sen}")
172-
196+
..
173197
174198
.. py:method:: sensitive_prune(pruned_flops, skip_vars=[], align=None)
175199
@@ -231,6 +255,6 @@ FPGMFilterPruner
231255
sen = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle")
232256
plan = pruner.sensitive_prune(0.5, align=8)
233257
print(f"plan: {plan}")
234-
258+
..
235259
236260

docs/zh_cn/api_cn/dygraph/pruners/l1norm_filter_pruner.rst

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
L1NormFilterPruner
22
==================
33

4-
.. py:class:: paddleslim.L1NormFilterPruner(model, inputs, sen_file=None)
4+
.. py:class:: paddleslim.L1NormFilterPruner(model, inputs, sen_file=None, opt=None)
55
66
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/release/2.0.0/paddleslim/dygraph/prune/l1norm_pruner.py#L14>`_
77

@@ -15,16 +15,40 @@ L1NormFilterPruner
1515

1616
- **sen_file(str)** - 存储敏感度信息的文件,需要指定为绝对路径。在调用当前剪裁器的 ``sensitive`` 方法时,敏感度信息会以增量的形式追加到文件 ``sen_file`` 中。如果用户不需要敏感度剪裁策略,可以将该选项设置为 ``None`` 。默认为None。
1717

18+
- **opt(paddle.optimizer.Optimizer)** - 动态图模型训练时用到的优化器。传入该参数是为了解决上述 ``model(paddle.nn.Layer)`` 不含有优化器,导致不能剪裁到优化器参数(例如 ``Momentum`` 中的 ``velocity`` )的问题。是否传入 ``optimizer`` 参数的逻辑为:若已经初始化了 ``optimizer`` 对象,则传入;否则,在调用了 ``pruner.prune_vars()`` 之后初始化 ``optimizer`` 。默认为None。
19+
1820
**返回:** 一个剪裁器实例。
1921

20-
**示例代码**
22+
**示例代码1**
2123

2224
.. code-block:: python
25+
26+
import paddle
2327
from paddle.vision.models import mobilenet_v1
2428
from paddleslim import L1NormFilterPruner
2529
net = mobilenet_v1(pretrained=False)
2630
pruner = L1NormFilterPruner(net, [1, 3, 224, 224])
31+
pruner.prune_var("conv2d_26.w_0", [0], pruned_ratio=0.5)
32+
optimizer = paddle.optimizer.Momentum(
33+
learning_rate=0.1,
34+
parameters=net.parameters())
35+
..
36+
37+
**示例代码2:**
38+
39+
.. code-block:: python
40+
41+
import paddle
42+
from paddle.vision.models import mobilenet_v1
43+
from paddleslim import L1NormFilterPruner
44+
net = mobilenet_v1(pretrained=False)
45+
optimizer = paddle.optimizer.Momentum(
46+
learning_rate=0.1,
47+
parameters=net.parameters())
48+
pruner = L1NormFilterPruner(net, [1, 3, 224, 224], opt=optimizer)
2749
..
50+
51+
**注意:** 上述两段代码展示了如何在 ``pruner`` 中是否调用 ``optimizer`` ,在示例代码1中,初始化 ``optimizer`` 时传入的 ``parameters`` 为剪裁后的 ``net.parameters()`` ,故无需在初始化 ``pruner`` 时传入 ``optimizer`` ;反之在示例代码2中, ``optimizer`` 中的 ``parameter`` 为剪裁前,故需要传入给 ``pruner`` 一并剪裁 ``optimizer`` 中的相关参数。
2852

2953
.. py:method:: prune_var(var_name, pruned_dims, pruned_ratio, apply="impretive")
3054
@@ -49,6 +73,7 @@ L1NormFilterPruner
4973
点击 `AIStudio <>`_ 执行以下示例代码。
5074

5175
.. code-block:: python
76+
5277
import paddle
5378
from paddle.vision.models import mobilenet_v1
5479
from paddleslim import L1NormFilterPruner
@@ -57,8 +82,7 @@ L1NormFilterPruner
5782
plan = pruner.prun_var("conv2d_26.w_0", [0])
5883
print(f"plan: {plan}")
5984
paddle.summary(net, (1, 3, 224, 224))
60-
61-
..
85+
..
6286
6387
.. py:method:: prune_vars(ratios, axis, apply="impretive")
6488
@@ -81,6 +105,7 @@ L1NormFilterPruner
81105
点击 `AIStudio <>`_ 执行以下示例代码。
82106

83107
.. code-block:: python
108+
84109
import paddle
85110
from paddle.vision.models import mobilenet_v1
86111
from paddleslim import L1NormFilterPruner
@@ -89,7 +114,6 @@ L1NormFilterPruner
89114
plan = pruner.prun_vars({"conv2d_26.w_0": 0.5}, [0])
90115
print(f"plan: {plan}")
91116
paddle.summary(net, (1, 3, 224, 224))
92-
93117
..
94118
95119
.. py:method:: sensitive(eval_func=None, sen_file=None, target_vars=None, skip_vars=[])
@@ -121,14 +145,15 @@ L1NormFilterPruner
121145
0.2: 0.4
122146
}
123147
}
124-
148+
..
125149
其中,``weight_0`` 是卷积层权重变量的名称, ``sensitivities['weight_0']`` 是一个字典, key是用 ``float`` 类型数值表示的剪裁率,value是对应剪裁率下整个模型的精度损失比例。
126150

127151
**示例:**
128152

129153
点击 `AIStudio <>`_ 执行以下示例代码。
130154

131155
.. code-block:: python
156+
132157
import paddle
133158
from paddle.vision.models import mobilenet_v1
134159
from paddleslim import L1NormFilterPruner
@@ -165,7 +190,7 @@ L1NormFilterPruner
165190
pruner = L1NormFilterPruner(net, [1, 3, 224, 224])
166191
sen = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle")
167192
print(f"sen: {sen}")
168-
193+
..
169194
170195
.. py:method:: sensitive_prune(pruned_flops, skip_vars=[], align=None)
171196
@@ -189,6 +214,7 @@ L1NormFilterPruner
189214
点击 `AIStudio <>`_ 执行以下示例代码。
190215

191216
.. code-block:: python
217+
192218
import paddle
193219
from paddle.vision.models import mobilenet_v1
194220
from paddleslim import L1NormFilterPruner
@@ -226,6 +252,4 @@ L1NormFilterPruner
226252
sen = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle")
227253
plan = pruner.sensitive_prune(0.5, align=8)
228254
print(f"plan: {plan}")
229-
230-
231-
255+
..

docs/zh_cn/api_cn/dygraph/pruners/l2norm_filter_pruner.rst

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
L2NormFilterPruner
22
==================
33

4-
.. py:class:: paddleslim.L2NormFilterPruner(model, inputs, sen_file=None)
4+
.. py:class:: paddleslim.L2NormFilterPruner(model, inputs, sen_file=None, opt=None)
55
66
`源代码 <https://github.com/PaddlePaddle/PaddleSlim/blob/release/2.0.0/paddleslim/dygraph/prune/l2norm_pruner.py>`_
77

@@ -15,16 +15,41 @@ L2NormFilterPruner
1515

1616
- **sen_file(str)** - 存储敏感度信息的文件,需要指定为绝对路径。在调用当前剪裁器的 ``sensitive`` 方法时,敏感度信息会以增量的形式追加到文件 ``sen_file`` 中。如果用户不需要敏感度剪裁策略,可以将该选项设置为 ``None`` 。默认为None。
1717

18+
- **opt(paddle.optimizer.Optimizer)** - 动态图模型训练时用到的优化器。传入该参数是为了解决上述 ``model(paddle.nn.Layer)`` 不含有优化器,导致不能剪裁到优化器参数(例如 ``Momentum`` 中的 ``velocity`` )的问题。是否传入 ``optimizer`` 参数的逻辑为:若已经初始化了 ``optimizer`` 对象,则传入;否则,在调用pruner.prune_vars()之后初始化 ``optimizer`` 。默认为None。
19+
1820
**返回:** 一个剪裁器实例。
1921

20-
**示例代码**
22+
**示例代码1**
2123

2224
.. code-block:: python
25+
26+
import paddle
2327
from paddle.vision.models import mobilenet_v1
2428
from paddleslim import L2NormFilterPruner
2529
net = mobilenet_v1(pretrained=False)
2630
pruner = L2NormFilterPruner(net, [1, 3, 224, 224])
31+
pruner.prune_var("conv2d_26.w_0", [0], pruned_ratio=0.5)
32+
optimizer = paddle.optimizer.Momentum(
33+
learning_rate=0.1,
34+
parameters=net.parameters())
2735
..
36+
37+
**示例代码2:**
38+
39+
.. code-block:: python
40+
41+
import paddle
42+
from paddle.vision.models import mobilenet_v1
43+
from paddleslim import L2NormFilterPruner
44+
net = mobilenet_v1(pretrained=False)
45+
optimizer = paddle.optimizer.Momentum(
46+
learning_rate=0.1,
47+
parameters=net.parameters())
48+
pruner = L2NormFilterPruner(net, [1, 3, 224, 224], opt=optimizer)
49+
..
50+
51+
**注意:** 上述两段代码展示了如何在 ``pruner`` 中是否调用 ``optimizer`` ,在示例代码1中,初始化 ``optimizer`` 时传入的 ``parameters`` 为剪裁后的 ``net.parameters()`` ,故无需在初始化 ``pruner`` 时传入 ``optimizer`` ;反之在示例代码2中, ``optimizer`` 中的 ``parameter`` 为剪裁前,故需要传入给 ``pruner`` 一并剪裁 ``optimizer`` 中的相关参数。
52+
2853

2954
.. py:method:: prune_var(var_name, pruned_dims, pruned_ratio, apply="impretive")
3055
@@ -49,6 +74,7 @@ L2NormFilterPruner
4974
点击 `AIStudio <>`_ 执行以下示例代码。
5075

5176
.. code-block:: python
77+
5278
import paddle
5379
from paddle.vision.models import mobilenet_v1
5480
from paddleslim import L2NormFilterPruner
@@ -81,6 +107,7 @@ L2NormFilterPruner
81107
点击 `AIStudio <>`_ 执行以下示例代码。
82108

83109
.. code-block:: python
110+
84111
import paddle
85112
from paddle.vision.models import mobilenet_v1
86113
from paddleslim import L2NormFilterPruner
@@ -121,6 +148,8 @@ L2NormFilterPruner
121148
0.2: 0.4
122149
}
123150
}
151+
152+
..
124153
125154
其中,``weight_0`` 是卷积层权重变量的名称, ``sensitivities['weight_0']`` 是一个字典, key是用 ``float`` 类型数值表示的剪裁率,value是对应剪裁率下整个模型的精度损失比例。
126155

@@ -129,6 +158,7 @@ L2NormFilterPruner
129158
点击 `AIStudio <>`_ 执行以下示例代码。
130159

131160
.. code-block:: python
161+
132162
import paddle
133163
from paddle.vision.models import mobilenet_v1
134164
from paddleslim import L2NormFilterPruner
@@ -165,7 +195,7 @@ L2NormFilterPruner
165195
pruner = L2NormFilterPruner(net, [1, 3, 224, 224])
166196
sen = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle")
167197
print(f"sen: {sen}")
168-
198+
..
169199
170200
.. py:method:: sensitive_prune(pruned_flops, skip_vars=[], align=None)
171201
@@ -226,6 +256,4 @@ L2NormFilterPruner
226256
sen = pruner.sensitive(eval_func=eval_fn, sen_file="./sen.pickle")
227257
plan = pruner.sensitive_prune(0.5, align=8)
228258
print(f"plan: {plan}")
229-
230-
231-
259+
..

docs/zh_cn/quick_start/dygraph/dygraph_pruning_tutorial.md

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,12 @@ FLOPs = paddle.flops(net, input_size=[1, 3, 32, 32], print_detail=True)
7474
代码如下所示:
7575

7676
```python
77-
pruner = L1NormFilterPruner(net, [1, 3, 32, 32])
77+
pruner = L1NormFilterPruner(net, [1, 3, 32, 32], opt=optimizer)
7878
pruner.prune_vars({'conv2d_22.w_0':0.5, 'conv2d_20.w_0':0.6}, axis=0)
7979
```
8080

8181
以上操作会按照网络结构中不同网路层的冗余程度对网络层进行不同程度的裁剪并修改网络模型结构。
82+
**注意:** 需要将`optimizer`传入`pruner`中,这是为了保证`optimizer`中的参数可以被剪裁到。例如:`momentum`中的`velocity`。但是如果在`pruner`后定义`optimizer`,则无需传入了,因为初始化`optimizer`时会指定`parameters=net.parameters()`
8283

8384
### 4.3 计算剪裁之后的FLOPs
8485

@@ -102,16 +103,6 @@ model.evaluate(val_dataset, batch_size=128, verbose=1)
102103
以下代码对裁剪过后的模型进行评估后执行了一个`epoch`的微调,再对微调过后的模型重新进行评估:
103104

104105
```python
105-
106-
optimizer = paddle.optimizer.Momentum(
107-
learning_rate=0.1,
108-
parameters=net.parameters())
109-
110-
model.prepare(
111-
optimizer,
112-
paddle.nn.CrossEntropyLoss(),
113-
paddle.metric.Accuracy(topk=(1, 5)))
114-
115106
model.fit(train_dataset, epochs=1, batch_size=128, verbose=1)
116107
model.evaluate(val_dataset, batch_size=128, verbose=1)
117108
```

docs/zh_cn/tutorials/pruning/dygraph/filter_pruning.md

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,15 @@ PaddleSlim提供了工具类`Pruner`来进行重要性分析和剪裁操作,
7979

8080
```python
8181
from paddleslim.dygraph import L1NormFilterPruner
82-
pruner = L1NormFilterPruner(net, [1, 3, 224, 224])
82+
pruner = L1NormFilterPruner(net, [1, 3, 224, 224], opt=optimizer)
8383
```
8484

85+
**注意:** 需要将`optimizer`传入`pruner`中,这是为了保证`optimizer`中的参数可以被剪裁到。例如:`momentum`中的`velocity`。但是如果在`pruner`后定义`optimizer`,则无需传入了,因为初始化`optimizer`时会指定`parameters=net.parameters()`
86+
8587
如果本地文件系统已有一个存储敏感度信息(见4.1节)的文件,声明`L1NormFilterPruner`对象时,可以通过指定`sen_file`选项加载计算好的敏感度信息,如下:
8688

8789
```python
88-
#pruner = L1NormFilterPruner(net, [1, 3, 224, 224]), sen_file="./sen.pickle")
90+
#pruner = L1NormFilterPruner(net, [1, 3, 224, 224]), sen_file="./sen.pickle", opt=optimizer)
8991
```
9092

9193
### 4.1 卷积重要性分析
@@ -167,13 +169,6 @@ print(f"before fine-tuning: {result}")
167169
对剪裁后的模型重新训练, 并再测试集上测试精度,如下:
168170

169171
```python
170-
optimizer = paddle.optimizer.Momentum(
171-
learning_rate=0.1,
172-
parameters=net.parameters())
173-
model.prepare(
174-
optimizer,
175-
paddle.nn.CrossEntropyLoss(),
176-
paddle.metric.Accuracy(topk=(1, 5)))
177172
model.fit(train_dataset, epochs=2, batch_size=128, verbose=1)
178173
result = model.evaluate(val_dataset,batch_size=128, log_freq=10)
179174
print(f"after fine-tuning: {result}")

0 commit comments

Comments
 (0)