README.md 11.3 KB
Newer Older
B
Bai Yifan 已提交
1
>运行该示例前请安装PaddleSlim和Paddle1.6或更高版本
2

G
Guanghua Yu 已提交
3
# 模型蒸馏教程
4 5 6

## 概述

B
Bai Yifan 已提交
7
该示例使用PaddleSlim提供的[蒸馏策略](https://paddlepaddle.github.io/PaddleSlim/algo/algo/#3)对检测库中的模型进行蒸馏训练。
8 9
在阅读该示例前,建议您先了解以下内容:

10
- [检测库的常规训练方法](https://github.com/PaddlePaddle/PaddleDetection)
B
Bai Yifan 已提交
11
- [PaddleSlim蒸馏API文档](https://paddlepaddle.github.io/PaddleSlim/api/single_distiller_api/)
12

13
已发布蒸馏模型见[压缩模型库](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/static/slim/README.md)
K
Kaipeng Deng 已提交
14

B
Bai Yifan 已提交
15 16
## 安装PaddleSlim
可按照[PaddleSlim使用文档](https://paddlepaddle.github.io/PaddleSlim/)中的步骤安装PaddleSlim
17

B
Bai Yifan 已提交
18
## 蒸馏策略说明
19

B
Bai Yifan 已提交
20
关于蒸馏API如何使用您可以参考PaddleSlim蒸馏API文档
21

B
Bai Yifan 已提交
22 23 24
### MobileNetV1-YOLOv3在VOC数据集上的蒸馏

这里以ResNet34-YOLOv3蒸馏训练MobileNetV1-YOLOv3模型为例,首先,为了对`student model``teacher model`有个总体的认识,进一步确认蒸馏的对象,我们通过以下命令分别观察两个网络变量(Variables)的名称和形状:
25 26

```python
B
Bai Yifan 已提交
27 28
# 观察student model的Variables
student_vars = []
29
for v in fluid.default_main_program().list_vars():
B
Bai Yifan 已提交
30 31 32 33 34 35 36 37
    try:
        student_vars.append((v.name, v.shape))
    except:
        pass
print("="*50+"student_model_vars"+"="*50)
print(student_vars)
# 观察teacher model的Variables
teacher_vars = []
38
for v in teacher_program.list_vars():
B
Bai Yifan 已提交
39 40 41 42 43 44
    try:
        teacher_vars.append((v.name, v.shape))
    except:
        pass
print("="*50+"teacher_model_vars"+"="*50)
print(teacher_vars)
45 46
```

B
Bai Yifan 已提交
47
经过对比可以发现,`student model``teacher model`输入到3个`yolov3_loss`的特征图分别为:
48 49 50

```bash
# student model
B
Bai Yifan 已提交
51
conv2d_20.tmp_1, conv2d_28.tmp_1, conv2d_36.tmp_1
52
# teacher model
B
Bai Yifan 已提交
53
conv2d_6.tmp_1, conv2d_14.tmp_1, conv2d_22.tmp_1
54 55 56
```


B
Bai Yifan 已提交
57 58 59 60 61 62
它们形状两两相同,且分别处于两个网络的输出部分。所以,我们用`l2_loss`对这几个特征图两两对应添加蒸馏loss。需要注意的是,teacher的Variable在merge过程中被自动添加了一个`name_prefix`,所以这里也需要加上这个前缀`"teacher_"`,merge过程请参考[蒸馏API文档](https://paddlepaddle.github.io/PaddleSlim/api/single_distiller_api/#merge)

```python
dist_loss_1 = l2_loss('teacher_conv2d_6.tmp_1', 'conv2d_20.tmp_1')
dist_loss_2 = l2_loss('teacher_conv2d_14.tmp_1', 'conv2d_28.tmp_1')
dist_loss_3 = l2_loss('teacher_conv2d_22.tmp_1', 'conv2d_36.tmp_1')
63 64
```

B
Bai Yifan 已提交
65
我们也可以根据上述操作为蒸馏策略选择其他loss,PaddleSlim支持的有`FSP_loss`, `L2_loss`, `softmax_with_cross_entropy_loss` 以及自定义的任何loss。
66

B
Bai Yifan 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
### MobileNetV1-YOLOv3在COCO数据集上的蒸馏

这里以ResNet34-YOLOv3作为蒸馏训练的teacher网络, 对MobileNetV1-YOLOv3结构的student网络进行蒸馏。

COCO数据集作为目标检测任务的训练目标难度更大,意味着teacher网络会预测出更多的背景bbox,如果直接用teacher的预测输出作为student学习的`soft label`会有严重的类别不均衡问题。解决这个问题需要引入新的方法,详细背景请参考论文:[Object detection at 200 Frames Per Second](https://arxiv.org/abs/1805.06361)

为了确定蒸馏的对象,我们首先需要找到student和teacher网络得到的`x,y,w,h,cls.objness`等变量在PaddlePaddle框架中的实际名称(var.name)。进而根据名称取出这些变量,用teacher得到的结果指导student训练。找到的所有变量如下:

```python
yolo_output_names = [
        'strided_slice_0.tmp_0', 'strided_slice_1.tmp_0',
        'strided_slice_2.tmp_0', 'strided_slice_3.tmp_0',
        'strided_slice_4.tmp_0', 'transpose_0.tmp_0', 'strided_slice_5.tmp_0',
        'strided_slice_6.tmp_0', 'strided_slice_7.tmp_0',
        'strided_slice_8.tmp_0', 'strided_slice_9.tmp_0', 'transpose_2.tmp_0',
        'strided_slice_10.tmp_0', 'strided_slice_11.tmp_0',
        'strided_slice_12.tmp_0', 'strided_slice_13.tmp_0',
        'strided_slice_14.tmp_0', 'transpose_4.tmp_0'
    ]
```

然后,就可以根据论文<<Object detection at 200 Frames Per Second>>的方法为YOLOv3中分类、回归、objness三个不同的head适配不同的蒸馏损失函数,并对分类和回归的损失函数用objness分值进行抑制,以解决前景背景类别不均衡问题。

90 91
## 训练

92
根据[PaddleDetection/tools/train.py](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/static/tools/train.py)编写压缩脚本`distill.py`
B
Bai Yifan 已提交
93
在该脚本中定义了teacher_model和student_model,用teacher_model的输出指导student_model的训练
94

B
Bai Yifan 已提交
95
### 执行示例
96

B
Bai Yifan 已提交
97
step1: 设置GPU卡
98

B
Bai Yifan 已提交
99 100 101
```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
```
102

B
Bai Yifan 已提交
103
step2: 开始训练
104

B
Bai Yifan 已提交
105
```bash
B
Bai Yifan 已提交
106
# yolov3_mobilenet_v1在voc数据集上蒸馏
B
Bai Yifan 已提交
107 108 109 110 111
python slim/distillation/distill.py \
    -c configs/yolov3_mobilenet_v1_voc.yml \
    -t configs/yolov3_r34_voc.yml \
    --teacher_pretrained https://paddlemodels.bj.bcebos.com/object_detection/yolov3_r34_voc.tar
```
112

B
Bai Yifan 已提交
113 114 115 116 117 118 119 120 121
```bash
# yolov3_mobilenet_v1在COCO数据集上蒸馏
python slim/distillation/distill.py \
    -c configs/yolov3_mobilenet_v1.yml \
    -o use_fine_grained_loss=true \
    -t configs/yolov3_r34.yml \
    --teacher_pretrained https://paddlemodels.bj.bcebos.com/object_detection/yolov3_r34.tar
```

B
Bai Yifan 已提交
122
如果要调整训练卡数,需要调整配置文件`yolov3_mobilenet_v1_voc.yml`中的以下参数:
123

B
Bai Yifan 已提交
124 125 126 127 128
- **max_iters:** 训练过程迭代总步数。
- **YOLOv3Loss.batch_size:** 该参数表示单张GPU卡上的`batch_size`, 总`batch_size`是GPU卡数乘以这个值, `batch_size`的设定受限于显存大小。
- **LeaningRate.base_lr:** 根据多卡的总`batch_size`调整`base_lr`,两者大小正相关,可以简单的按比例进行调整。
- **LearningRate.schedulers.PiecewiseDecay.milestones:** 请根据batch size的变化对其调整。
- **LearningRate.schedulers.PiecewiseDecay.LinearWarmup.steps:** 请根据batch size的变化对其进行调整。
129

B
Bai Yifan 已提交
130
以下为4卡训练示例,通过命令行-o参数覆盖`yolov3_mobilenet_v1_voc.yml`中的参数, 修改GPU卡数后应尽量确保总batch_size(GPU卡数\*YoloTrainFeed.batch_size)不变, 以确保训练效果不因bs大小受影响:
131

B
Bai Yifan 已提交
132 133
```bash
# yolov3_mobilenet_v1在VOC数据集上蒸馏
B
Bai Yifan 已提交
134 135 136 137
CUDA_VISIBLE_DEVICES=0,1,2,3
python slim/distillation/distill.py \
    -c configs/yolov3_mobilenet_v1_voc.yml \
    -t configs/yolov3_r34_voc.yml \
B
Bai Yifan 已提交
138
    -o YOLOv3Loss.batch_size=16 \
B
Bai Yifan 已提交
139 140
    --teacher_pretrained https://paddlemodels.bj.bcebos.com/object_detection/yolov3_r34_voc.tar
```
141

B
Bai Yifan 已提交
142 143 144 145 146 147 148 149 150
```bash
# yolov3_mobilenet_v1在COCO数据集上蒸馏
CUDA_VISIBLE_DEVICES=0,1,2,3
python slim/distillation/distill.py \
    -c configs/yolov3_mobilenet_v1.yml \
    -t configs/yolov3_r34.yml \
    -o use_fine_grained_loss=true YOLOv3Loss.batch_size=16 \
    --teacher_pretrained https://paddlemodels.bj.bcebos.com/object_detection/yolov3_r34.tar
```
151 152 153



B
Bai Yifan 已提交
154
### 保存断点(checkpoint)
155

B
Bai Yifan 已提交
156
蒸馏任务执行过程中会自动保存断点。如果需要从断点继续训练请用`-r`参数指定checkpoint路径,示例如下:
157

B
Bai Yifan 已提交
158
```bash
B
Bai Yifan 已提交
159
# yolov3_mobilenet_v1在VOC数据集上恢复断点
B
Bai Yifan 已提交
160 161 162 163 164 165
python -u slim/distillation/distill.py \
-c configs/yolov3_mobilenet_v1_voc.yml \
-t configs/yolov3_r34_voc.yml \
-r output/yolov3_mobilenet_v1_voc/10000 \
--teacher_pretrained https://paddlemodels.bj.bcebos.com/object_detection/yolov3_r34_voc.tar
```
166

B
Bai Yifan 已提交
167 168 169 170 171 172 173 174 175
```bash
# yolov3_mobilenet_v1在COCO数据集上恢复断点
python -u slim/distillation/distill.py \
-c configs/yolov3_mobilenet_v1.yml \
-t configs/yolov3_r34.yml \
-o use_fine_grained_loss=true \
-r output/yolov3_mobilenet_v1/10000 \
--teacher_pretrained https://paddlemodels.bj.bcebos.com/object_detection/yolov3_r34.tar
```
176 177 178



B
Bai Yifan 已提交
179 180
## 评估

181
每隔`snap_shot_iter`步后会保存一个checkpoint模型可以用于评估,使用PaddleDetection目录下[tools/eval.py](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/static/tools/eval.py)评估脚本,并指定`weights`为训练得到的模型路径
182 183

运行命令为:
B
Bai Yifan 已提交
184
```bash
B
Bai Yifan 已提交
185
# yolov3_mobilenet_v1在VOC数据集上评估
B
Bai Yifan 已提交
186 187 188
export CUDA_VISIBLE_DEVICES=0
python -u tools/eval.py -c configs/yolov3_mobilenet_v1_voc.yml \
       -o weights=output/yolov3_mobilenet_v1_voc/model_final \
189 190
```

B
Bai Yifan 已提交
191 192 193 194 195 196 197
```bash
# yolov3_mobilenet_v1在COCO数据集上评估
export CUDA_VISIBLE_DEVICES=0
python -u tools/eval.py -c configs/yolov3_mobilenet_v1.yml \
       -o weights=output/yolov3_mobilenet_v1/model_final \
```

B
Bai Yifan 已提交
198
## 预测
199

200
每隔`snap_shot_iter`步后保存的checkpoint模型也可以用于预测,使用PaddleDetection目录下[tools/infer.py](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/static/tools/infer.py)评估脚本,并指定`weights`为训练得到的模型路径
201

B
Bai Yifan 已提交
202
### Python预测
203

B
Bai Yifan 已提交
204 205
运行命令为:
```
B
Bai Yifan 已提交
206
# 使用yolov3_mobilenet_v1_voc模型进行预测
B
Bai Yifan 已提交
207 208 209 210 211 212 213
export CUDA_VISIBLE_DEVICES=0
python -u tools/infer.py -c configs/yolov3_mobilenet_v1_voc.yml \
                    --infer_img=demo/000000570688.jpg \
                    --output_dir=infer_output/ \
                    --draw_threshold=0.5 \
                    -o weights=output/yolov3_mobilenet_v1_voc/model_final
```
214

B
Bai Yifan 已提交
215 216 217 218 219 220 221 222 223 224
```
# 使用yolov3_mobilenet_v1_coco模型进行预测
export CUDA_VISIBLE_DEVICES=0
python -u tools/infer.py -c configs/yolov3_mobilenet_v1.yml \
                    --infer_img=demo/000000570688.jpg \
                    --output_dir=infer_output/ \
                    --draw_threshold=0.5 \
                    -o weights=output/yolov3_mobilenet_v1/model_final
```

B
Bai Yifan 已提交
225
## 示例结果
226

B
Bai Yifan 已提交
227
### MobileNetV1-YOLO-V3-VOC
228

B
Bai Yifan 已提交
229 230 231
| FLOPS |输入尺寸|每张GPU图片个数|推理时间(fps)|Box AP|下载|
|:-:|:-:|:-:|:-:|:-:|:-:|
|baseline|608     |16|104.291|76.2|[下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v1_voc.tar)|
B
Bai Yifan 已提交
232
|蒸馏后|608 |16|106.914|79.0|[下载链接](https://paddlemodels.bj.bcebos.com/PaddleSlim/yolov3_mobilenetv1_voc_distilled.tar)|
B
Bai Yifan 已提交
233
|baseline|416 |16|-|76.7|[下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v1_voc.tar)|
B
Bai Yifan 已提交
234
|蒸馏后|416 |16|-|78.2|[下载链接](https://paddlemodels.bj.bcebos.com/PaddleSlim/yolov3_mobilenetv1_voc_distilled.tar)|
B
Bai Yifan 已提交
235
|baseline|320 |16|-|75.3|[下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v1_voc.tar)|
B
Bai Yifan 已提交
236
|蒸馏后|320 |16|-|75.5|[下载链接](https://paddlemodels.bj.bcebos.com/PaddleSlim/yolov3_mobilenetv1_voc_distilled.tar)|
237

B
Bai Yifan 已提交
238
> 蒸馏后的结果用ResNet34-YOLO-V3做teacher,4GPU总batch_size64训练90000 iter得到
B
Bai Yifan 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251

### MobileNetV1-YOLO-V3-COCO

| FLOPS |输入尺寸|每张GPU图片个数|推理时间(fps)|Box AP|下载|
|:-:|:-:|:-:|:-:|:-:|:-:|
|baseline|608     |16|78.302|29.3|[下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v1_voc.tar)|
|蒸馏后|608 |16|78.523|31.4|[下载链接](https://paddlemodels.bj.bcebos.com/PaddleSlim/yolov3_mobilenetv1_coco_distilled.tar)|
|baseline|416 |16|-|29.3|[下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v1_voc.tar)|
|蒸馏后|416 |16|-|30.0|[下载链接](https://paddlemodels.bj.bcebos.com/PaddleSlim/yolov3_mobilenetv1_coco_distilled.tar)|
|baseline|320 |16|-|27.0|[下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v1_voc.tar)|
|蒸馏后|320 |16|-|27.1|[下载链接](https://paddlemodels.bj.bcebos.com/PaddleSlim/yolov3_mobilenetv1_coco_distilled.tar)|

> 蒸馏后的结果用ResNet34-YOLO-V3做teacher,4GPU总batch_size64训练600000 iter得到