README.md 7.2 KB
Newer Older
1
# 非结构化稀疏 -- 动态图剪裁(包括按照阈值和比例剪裁两种模式)示例
M
minghaoBD 已提交
2 3 4

## 简介

5 6
在模型压缩中,常见的稀疏方式为结构化和非结构化稀疏,前者在某个特定维度(特征通道、卷积核等等)上进行稀疏化操作;后者以每一个参数为单元进行稀疏化,并不会改变参数矩阵的形状,所以更加依赖于硬件对稀疏后矩阵运算的加速能力。本目录即在PaddlePaddle和PaddleSlim框架下开发的非结构化稀疏算法,`MobileNetV1``ImageNet`上的稀疏化实验中,剪裁率55.19%,达到无损的表现。

7
本示例将演示基于不同的剪裁模式(阈值/比例)进行非结构化稀疏。默认会自动下载并使用`CIFAR-10`数据集。当前示例目前支持`MobileNetV1`,使用其他模型可以按照下面的训练代码示例进行API调用。此外,为保证大稀疏度(75%+)下模型的精度,我们引入了`GMP`训练策略,详细的介绍和使用请参照[介绍](../../unstructured_prune/README_GMP.md)
M
minghaoBD 已提交
8 9 10 11

## 版本要求
```bash
python3.5+
C
ceci3 已提交
12 13
paddlepaddle>=2.4rc0
paddleslim>=2.4rc
M
minghaoBD 已提交
14 15 16 17
```

请参照github安装[paddlepaddle](https://github.com/PaddlePaddle/Paddle)[paddleslim](https://github.com/PaddlePaddle/PaddleSlim)

18 19 20 21 22 23 24 25 26 27
## 数据准备

本示例支持`CIFAR-10``ImageNet`两种数据。默认情况下,会自动下载并使用`CIFAR-10`数据,如果需要使用`ImageNet`数据。请按以下步骤操作:

- 根据分类模型中[ImageNet数据准备文档](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification#%E6%95%B0%E6%8D%AE%E5%87%86%E5%A4%87)下载数据到`PaddleSlim/demo/data/ILSVRC2012`路径下。
- 使用`train.py``evaluate.py`运行脚本时,指定`--data`选项为`imagenet`

如果想要使用自定义的数据集,需要重写`../../imagenet_reader.py`文件,并在`train.py`中调用实现。

## 下载预训练模型
M
minghaoBD 已提交
28

29 30 31 32 33 34 35
该示例中直接使用`paddle.vision.models`模块提供的针对`ImageNet`分类任务的预训练模型。 对预训练好的模型剪裁后,需要在目标数据集上进行重新训练,以便恢复因剪裁损失的精度。

## 自定义稀疏化方法

默认根据参数的绝对值大小进行稀疏化,且不稀疏归一化层参数。如果开发者想更改相应的逻辑,可按照下述操作:

- 开发者可以通过重写`paddleslim.dygraph.prune.unstructured_pruner.py`中的`UnstructuredPruner.mask_parameters()``UnstructuredPruner.update_threshold()`来定义自己的非结构化稀疏策略(目前为剪裁掉绝对值小的parameters)。
36
- 开发可以在初始化`UnstructuredPruner`时,传入自定义的`skip_params_func`,来定义哪些参数不参与剪裁。`skip_params_func`示例代码如下(路径:`paddleslim.dygraph.prune.unstructured_pruner._get_skip_params())`。默认为所有的归一化层的参数和 `bias` 不参与剪裁。
M
minghaoBD 已提交
37 38

```python
39 40 41 42
NORMS_ALL = [ 'BatchNorm', 'GroupNorm', 'LayerNorm', 'SpectralNorm', 'BatchNorm1D',
    'BatchNorm2D', 'BatchNorm3D', 'InstanceNorm1D', 'InstanceNorm2D',
    'InstanceNorm3D', 'SyncBatchNorm', 'LocalResponseNorm' ]

M
minghaoBD 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55
def _get_skip_params(model):
    """
    This function is used to check whether the given model's layers are valid to be pruned.
    Usually, the convolutions are to be pruned while we skip the normalization-related parameters.
    Deverlopers could replace this function by passing their own when initializing the UnstructuredPuner instance.

    Args:
      - model(Paddle.nn.Layer): the current model waiting to be checked.
    Return:
      - skip_params(set<String>): a set of parameters' names
    """
    skip_params = set()
    for _, sub_layer in model.named_sublayers():
56
        if type(sub_layer).__name__.split('.')[-1] in NORMS_ALL:
M
minghaoBD 已提交
57
            skip_params.add(sub_layer.full_name())
58 59
        for param in sub_layer.parameters(include_sublayers=False):
            if len(param.shape) == 1: skip_params.add(param.name)
M
minghaoBD 已提交
60 61 62
    return skip_params
```

63 64 65 66
## 训练

按照阈值剪裁:
```bash
67
python train.py --data imagenet --lr 0.05 --pruning_mode threshold --threshold 0.01
68 69 70 71
```

按照比例剪裁(训练速度较慢,推荐按照阈值剪裁):
```bash
72
python train.py --data imagenet --lr 0.05 --pruning_mode ratio --ratio 0.55
73 74 75
```

GPU多卡训练:
M
minghaoBD 已提交
76
```bash
77
export CUDA_VISIBLE_DEVICES=0,1,2,3
78
python -m paddle.distributed.launch \
79 80
--gpus="0,1,2,3" \
--log_dir="train_mbv1_imagenet_threshold_001_log" \
81
train.py --data imagenet --lr 0.05 --pruning_mode threshold --threshold 0.01 --batch_size 64
M
minghaoBD 已提交
82 83
```

84 85
**注意**,这里的batch_size为单卡上的。

86
恢复训练(请替代命令中的`dir/to/the/saved/pruned/model``LAST_EPOCH`):
M
minghaoBD 已提交
87
```bash
88 89
python train.py --data imagenet --lr 0.05 --pruning_mode threshold --threshold 0.01 \
                                            --pretrained_model dir/to/the/saved/pruned/model --resume_epoch LAST_EPOCH
90 91 92 93
```

## 推理:
```bash
94
python evaluate.py --pruned_model models/model.pdparams --data imagenet
M
minghaoBD 已提交
95 96
```

97 98
**注意**,上述`pruned_model` 参数应该指向pdparams文件。

M
minghaoBD 已提交
99 100 101 102
剪裁训练代码示例:
```python
model = mobilenet_v1(num_classes=class_dim, pretrained=True)
#STEP1: initialize the pruner
103
pruner = UnstructuredPruner(model, mode='threshold', threshold=0.01)
M
minghaoBD 已提交
104 105 106 107 108 109

for epoch in range(epochs):
    for batch_id, data in enumerate(train_loader):
        loss = calculate_loss()
        loss.backward()
        opt.step()
110
        learning_rate.step()
M
minghaoBD 已提交
111 112 113 114 115 116 117 118 119 120 121 122
        opt.clear_grad()
        #STEP2: update the pruner's threshold given the updated parameters
        pruner.step()

    if epoch % args.test_period == 0:
        #STEP3: before evaluation during training, eliminate the non-zeros generated by opt.step(), which, however, the cached masks setting to be zeros.
        pruner.update_params()
        eval(epoch)

    if epoch % args.model_period == 0:
        # STEP4: same purpose as STEP3
        pruner.update_params()
123 124
        paddle.save(model.state_dict(), "model.pdparams")
        paddle.save(opt.state_dict(), "model.pdopt")
M
minghaoBD 已提交
125 126 127 128 129
```

剪裁后测试代码示例:
```python
model = mobilenet_v1(num_classes=class_dim, pretrained=True)
130
model.set_state_dict(paddle.load("model.pdparams"))
131 132
#注意,total_sparse为静态方法(static method),可以不创建实例(instance)直接调用,方便只做测试的写法。
print(UnstructuredPruner.total_sparse(model))
M
minghaoBD 已提交
133 134 135 136 137
test()
```

更多使用参数请参照shell文件或者运行如下命令查看:
```bash
138 139
python train.py --h
python evaluate.py --h
M
minghaoBD 已提交
140 141
```

142
## 实验结果
M
minghaoBD 已提交
143 144 145 146 147

| 模型 | 数据集 | 压缩方法 | 压缩率| Top-1/Top-5 Acc | lr | threshold | epoch |
|:--:|:---:|:--:|:--:|:--:|:--:|:--:|:--:|
| MobileNetV1 | ImageNet | Baseline | - | 70.99%/89.68% | - | - | - |
| MobileNetV1 | ImageNet |   ratio  | -55.19% | 70.87%/89.80% (-0.12%/+0.12%) | 0.005 | - | 68 |
148
| MobileNetV1 | ImageNet |   threshold  | -49.49% | 71.22%/89.78% (+0.23%/+0.10%) | 0.05 | 0.01 | 93 |
149 150
| MobileNetV1 | Imagenet | ratio, 1x1conv, GMP | 75% | 70.49%/89.48% (-0.5%/-0.20%) | 0.005 | - | 108 |
| MobileNetV1 | Imagenet | ratio, 1x1conv, GMP | 80% | 70.02%/89.26% (-0.97%/-0.42%) | 0.005 | - | 108 |
M
minghaoBD 已提交
151
| YOLO v3     |  VOC     | - | - |76.24% | - | - | - |
152
| YOLO v3     |  VOC     |threshold | -56.50% | 77.21% (+0.97%) | 0.001 | 0.01 | 150k iterations |