add finetune doc

pull/33/head
wangshipeng01 2020-04-17 10:34:58 +00:00
parent e33baa2b7c
commit 1d3b8e71c9
4 changed files with 157 additions and 45 deletions

View File

@ -3,21 +3,26 @@ import numpy as np
import os import os
import sys import sys
""" """.mat files data format
Usage: python generate_flower_list.py ./jpg train > train_list.txt imagelabel.mat
python generate_flower_list.py ./jpg valid > val_list.txt jpg_name 1 2 3 ...
""" label 32 12 66 ...
setid.mat
jpg_name(10 records in a class) 24 6 100 65 32 ...
label 4 ...
"""
"""
Usage:
python generate_flower_list.py prefix_folder mode
python generate_flower_list.py jpg train > train_list.txt
python generate_flower_list.py jpg valid > val_list.txt
"""
data_path = sys.argv[1] data_path = sys.argv[1]
imagelabels_path='./imagelabels.mat' imagelabels_path='./imagelabels.mat'
setid_path='./setid.mat' setid_path='./setid.mat'
"""
imagelabel.mat
jpg_name 1 2 3 ...
label 32 12 66 ...
"""
labels = scipy.io.loadmat(imagelabels_path) labels = scipy.io.loadmat(imagelabels_path)
labels = np.array(labels['labels'][0]) labels = np.array(labels['labels'][0])
setid = scipy.io.loadmat(setid_path) setid = scipy.io.loadmat(setid_path)
@ -27,13 +32,6 @@ d['train'] = np.array(setid['trnid'][0])
d['valid'] = np.array(setid['valid'][0]) d['valid'] = np.array(setid['valid'][0])
d['test']=np.array(setid['tstid'][0]) d['test']=np.array(setid['tstid'][0])
"""
setid.mat
jpg_name 24 6 100 65 32 ...
label 4 ...
"""
for id in d[sys.argv[2]]: for id in d[sys.argv[2]]:
message = str(data_path)+"/image_"+str(id).zfill(5)+" "+str(labels[id-1]) message = str(data_path)+"/image_"+str(id).zfill(5)+".jpg "+str(labels[id-1])
print(message) print(message)

View File

@ -3,23 +3,25 @@
--- ---
## 1.简介 ## 1.简介
PaddleClas支持ImageNet1000和Flower数据分类任务 本文档介绍ImageNet1k和Flower102数据准备过程
PaddleClas提供了丰富的预训练模型支持的模型列表请参考[模型库](../models/models_intro.md) PaddleClas提供了丰富的预训练模型支持的模型列表请参考[模型库](../models/models_intro.md)
## 2.数据集准备 ## 2.数据集准备
数据集 | 训练集大小 | 测试集大小 | 类别数 | 备注| 数据集 | 训练集大小 | 测试集大小 | 类别数 | 备注|
:------:|:---------------:|:---------------------:|:-----------:|:-----------: :------:|:---------------:|:---------------------:|:-----------:|:-----------:
Flowers|1k | 6k | 102 | [Flower102](https://www.robots.ox.ac.uk/~vgg/data/flowers/102/)|1k | 6k | 102 |
[ImageNet](http://www.image-net.org/challenges/LSVRC/2012/)|1.2M| 50k | 1000 | [ImageNet1k](http://www.image-net.org/challenges/LSVRC/2012/)|1.2M| 50k | 1000 |
数据格式 数据格式
PaddleClas加载PaddleClas/dataset/中的数据通过指定data_dir和file_list来进行加载
PaddleClas加载PaddleClas/dataset/中的数据请将下载后的数据按下面格式组织放置到PaddleClas/dataset/中。 ### ImageNet1k
从官方下载数据后,按如下组织数据
```bash ```bash
PaddleClas/dataset/imagenet PaddleClas/dataset/imagenet/
|_ train |_ train/
| |_ n01440764 | |_ n01440764
| | |_ n01440764_10026.JPEG | | |_ n01440764_10026.JPEG
| | |_ ... | | |_ ...
@ -28,29 +30,39 @@ PaddleClas/dataset/imagenet
| |_ n15075141 | |_ n15075141
| |_ ... | |_ ...
| |_ n15075141_9993.JPEG | |_ n15075141_9993.JPEG
|_ val |_ val/
| |_ ILSVRC2012_val_00000001.JPEG | |_ ILSVRC2012_val_00000001.JPEG
| |_ ... | |_ ...
| |_ ILSVRC2012_val_00050000.JPEG | |_ ILSVRC2012_val_00050000.JPEG
|_ train_list.txt |_ train_list.txt
|_ val_list.txt |_ val_list.txt
``` ```
### Flower
从VGG官方网站下载后的数据解压后包括
jpg/
setid.mat
imagelabels.mat
将以上文件放置在PaddleClas/dataset/flower102/下
通过运行generate_flower_list.py生成train_list.txt和val_list.txt
```bash ```bash
PaddleClas/dataset/flower python generate_flower_list.py jpg train > train_list.txt
|_ train python generate_flower_list.py jpg valid > val_list.txt
```
按照如下结构组织数据:
```bash
PaddleClas/dataset/flower102/
|_ jpg/
| |_ image_03601.jpg | |_ image_03601.jpg
| |_ ... | |_ ...
| |_ image_07073.jpg
|_ val
| |_ image_04121.jpg
| |_ ...
| |_ image_02355.jpg | |_ image_02355.jpg
|_ train_list.txt |_ train_list.txt
|_ val_list.txt |_ val_list.txt
``` ```
或是通过软链接将数据从实际地址链接到PaddleClas/dataset/下 或是通过软链接将数据从实际地址链接到PaddleClas/dataset/下
```bash ```bash

View File

@ -0,0 +1,110 @@
# 模型微调
本文档将介绍如何使用PaddleClas进行模型微调finetune
模型微调使用PaddleClas提供的预训练模型可以节省从头训练的计算资源和时间并提高准确率。
> 在使用ResNet50_vd_ssld蒸馏模型对flower102数据进行模型微调仅需要3分钟V100 单卡top1即可达到94.96%
模型微调大致包括如下四个步骤:
- 初始化预训练模型
- 剔除FC层
- 更新参数
- 新的训练策略
## 初始化预训练模型
这里我们以ResNet50_vd和ResNet50_vd_ssld预训练模型对flower102数据集进行微调
ResNet50_vd 在ImageNet1k数据集上训练 top1 acc79.1% 模型详细信息参考[模型库](https://paddleclas.readthedocs.io/zh_CN/latest/models/ResNet_and_vd.html)
ResNet50_vd_ssld 在ImageNet1k数据集训练的蒸馏模型 top1 82.4% 模型详细信息参考[模型库](https://paddleclas.readthedocs.io/zh_CN/latest/models/ResNet_and_vd.html)
flower数据集相关信息参考[数据文档](data.md)
指定pretrained_model参数初始化预训练模型
ResNet50_vd
```bash
python -m paddle.distributed.launch \
--selected_gpus="0" \
tools/train.py \
-c ./configs/finetune/ResNet50_vd_finetune.yaml
-o pretrained_model= ResNet50_vd预训练模型
```
ResNet50_vd_ssld
```bash
python -m paddle.distributed.launch \
--selected_gpus="0" \
tools/train.py \
-c ./configs/finetune/ResNet50_vd_ssld_finetune.yaml
-o pretrained_model= ResNet50_vd_ssld预训练模型
```
##剔除FC层
由于新的数据集类别数Flower102102类和ImgaeNet1k数据1000类不一致一般需要对分类网络的最后FC层进行调整PaddleClas默认剔除所有形状不一样的层
```python
#excerpt from PaddleClas/ppcls/utils/save_load.py
def load_params(exe, prog, path):
# ...
ignore_set = set()
state = _load_state(path)
# 剔除预训练模型和模型间形状不一致的参数
all_var_shape = {}
for block in prog.blocks:
for param in block.all_parameters():
all_var_shape[param.name] = param.shape
ignore_set.update([
name for name, shape in all_var_shape.items()
if name in state and shape != state[name].shape
])
# 用于迁移学习的代码段已被省略 ...
if len(ignore_set) > 0:
for k in ignore_set:
if k in state:
# 剔除参数
del state[k]
fluid.io.set_program_state(prog, state)
```
在将shape不一致的层进行剔除正确加载预训练模型后我们要选择需要更新的参数来让优化器进行参数更新。
## 更新参数
首先,分类网络中的卷积层大致可以分为
- ```浅层卷积层```:用于提取基础特征
- ```深层卷积层```:用于提取抽象特征
- ```FC层```:进行特征组合
其次,在衡量数据集大小差别和数据集的相似程度后,我们一般遵循如下的规则进行参数更新:
- 1. 新的数据集很小,在类别,具体种类上和原数据很像。由于新数据集很小,这里可能出现过拟合的问题;由于数据很像,可以认为预训练模型的深层特征仍然会起作用,只需要训练一个最终的```FC层```即可。
- 2. 新的数据集很大,在类别,具体种类上和原数据很像。推荐训练网络中全部层的参数。
- 3. 新的数据集很小但是和原数据不相像,可以冻结网络中初始层的参数更新```stop_gradient=True```,对较高层进行重新训练。
- 4. 新的数据集很大但是和原数据不相像,这时候预训练模型可能不会生效,需要从头训练。
PaddleClas模型微调默认更新所有层参数。
## 新的训练策略
1. 学习率
由于已经加载了预训练模型对于从头训练的随机初始化参数来讲模型中的参数已经具备了一定的分类能力所以建议使用与从头训练相比更小的学习率例如减小10倍。
2. 类别数和总图片数调整为新数据集数据
3. 调整训练轮数,由于不需要从头开始训练,一般相对减少模型微调的训练轮数
## 模型微调结果
在使用ResNet50_vd预训练模型对flower102数据进行模型微调后top1 acc 达到 92.71%
在使用ResNet50_vd_ssld预训练模型对flower102数据进行模型微调后top1 acc 达到94.96%

View File

@ -16,15 +16,17 @@ export PYTHONPATH=path_to_PaddleClas:$PYTHONPATH
PaddleClas 提供模型训练与评估脚本tools/train.py和tools/eval.py PaddleClas 提供模型训练与评估脚本tools/train.py和tools/eval.py
### 2.1 模型训练 ### 2.1 模型训练
以flower102数据为例按如下方式启动模型训练flower数据集准备请参考[数据集准备](./data.md)
```bash ```bash
# PaddleClas通过launch方式启动多卡多进程训练 # PaddleClas通过launch方式启动多卡多进程训练
# 通过设置FLAGS_selected_gpus 指定GPU运行卡号 # 通过设置FLAGS_selected_gpus 指定GPU运行卡号
python -m paddle.distributed.launch \ python -m paddle.distributed.launch \
--selected_gpus="0,1,2,3" \ --selected_gpus="0,1,2,3" \
--log_dir=log_ResNet50 \ --log_dir=log_ResNet50_vd \
tools/train.py \ tools/train.py \
-c ./configs/ResNet/ResNet50.yaml -c ./configs/flower.yaml
``` ```
- 输出日志示例如下: - 输出日志示例如下:
@ -40,7 +42,7 @@ python -m paddle.distributed.launch \
--selected_gpus="0,1,2,3" \ --selected_gpus="0,1,2,3" \
--log_dir=log_ResNet50_vd \ --log_dir=log_ResNet50_vd \
tools/train.py \ tools/train.py \
-c ./configs/ResNet/ResNet50_vd.yaml \ -c ./configs/flower.yaml \
-o use_mix=1 -o use_mix=1
``` ```
@ -54,18 +56,8 @@ epoch:0 train step:522 loss:1.6330 lr:0.100000 elapse:0.210
或是直接修改模型对应的yaml配置文件具体配置参数参考[配置文档](config.md)。 或是直接修改模型对应的yaml配置文件具体配置参数参考[配置文档](config.md)。
### 2.3 模型微调 ### 2.3 模型微调
模型微调请参照[模型微调文档](./finetune.md)
您可以通过如下命令进行模型微调,通过指定--pretrained_model参数加载预训练模型
```bash
python -m paddle.distributed.launch \
--selected_gpus="0,1,2,3" \
--log_dir=log_ResNet50_vd \
train.py \
-c ../configs/ResNet/ResNet50_vd.yaml \
-o pretrained_model= 预训练模型路径\
```
### 2.2 模型评估 ### 2.2 模型评估