提交 58e8c69c 编写于 作者: W WuHaobo
......@@ -5,7 +5,7 @@
## 简介
<div align="center">
<img src="docs/images/main_features.png" width="700">
<img src="docs/images/main_features.png" width="800">
</div>
## 丰富的模型库
......@@ -62,8 +62,6 @@ PaddleClas提供了上述8种数据增广算法的复现和在统一实验环境
src="docs/images/image_aug/main_image_aug.png" width="600">
</div>
- TODO
- [ ] 更多的优化器支持和效果验证
## 开始使用
PaddleClas的安装说明、模型训练、预测、评估以及模型微调(finetune)请参考文档教程中的[**初级使用章节**](https://paddleclas.readthedocs.io/zh_CN/latest/tutorials/index.html),SSLD知识蒸馏和数据增广的高阶使用正在持续更新中。
......@@ -72,11 +70,15 @@ PaddleClas的安装说明、模型训练、预测、评估以及模型微调(f
### 10万类图像分类预训练模型
在实际应用中,由于训练数据匮乏,往往将ImageNet1K数据集训练的分类模型作为预训练模型,进行图像分类的迁移学习。然而ImageNet1K数据集的类别只有1000种,预训练模型的特征迁移能力有限。因此百度自研了一个有语义体系的、粒度有粗有细的10w级别的Tag体系,通过人工或半监督方式,至今收集到 5500w+图片训练数据;该系统是国内甚至世界范围内最大规模的图片分类体系和训练集合。PaddleClas提供了在该数据集上训练的ResNet50_vd的模型。下表显示了一些实际应用场景中,使用ImageNet预训练模型和上述10万类图像分类预训练模型的效果比对,使用10万类图像分类预训练模型,识别准确率最高可以提升30%。
<div align="center">
<img
src="docs/images/10w_cls.png" width="450">
</div>
| 数据集 | 数据统计 | ImageNet预训练模型 | 10万类图像分类预训练模型 |
|:--:|:--:|:--:|:--:|
| 花卉 | class_num:102<br/>train/val:5789/2396 | 0.7779 | 0.9892 |
| 手绘简笔画 | class_num:18<br/>train/val:1007/432 | 0.8785 | 0.9107 |
| 植物叶子 | class_num:6<br/>train/val:5256/2278 | 0.8212 | 0.8385 |
| 集装箱车辆 | class_num:115<br/>train/val:4879/2094 | 0.623 | 0.9524 |
| 椅子 | class_num:5<br/>train/val:169/784 | 0.8557 | 0.9077 |
| 地质 | class_num:4<br/>train/val:671/296 | 0.5719 | 0.6781 |
10万类图像分类预训练模型下载地址如下,更多的相关内容请参考文档教程中的[**图像分类迁移学习章节**](https://paddleclas.readthedocs.io/zh_CN/latest/application/transfer_learning.html#id1)
......
mode: 'valid'
ARCHITECTURE:
name: ""
name: "ResNet50_vd"
pretrained_model: ""
pretrained_model: "./pretrained_model/ResNet50_vd_pretrained"
classes_num: 1000
total_images: 1281167
topk: 5
......@@ -11,8 +11,8 @@ image_shape: [3, 224, 224]
VALID:
batch_size: 16
num_workers: 4
file_list: "../dataset/ILSVRC2012/val_list.txt"
data_dir: "../dataset/ILSVRC2012/"
file_list: "./dataset/ILSVRC2012/val_list.txt"
data_dir: "./dataset/ILSVRC2012/"
shuffle_seed: 0
transforms:
- DecodeImage:
......
mode: 'train'
ARCHITECTURE:
name: 'ResNet50_vd'
pretrained_model:
model_save_dir: "./output/"
classes_num: 102
total_images: 1020
save_interval: 10
validate: True
valid_interval: 1
epochs: 40
topk: 5
image_shape: [3, 224, 224]
ls_epsilon: 0.1
LEARNING_RATE:
function: 'Cosine'
params:
lr: 0.00375
OPTIMIZER:
function: 'Momentum'
params:
momentum: 0.9
regularizer:
function: 'L2'
factor: 0.000001
TRAIN:
batch_size: 32
num_workers: 1
file_list: "./dataset/flowers102/train_list.txt"
data_dir: "./dataset/flowers102"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- RandCropImage:
size: 224
- RandFlipImage:
flip_code: 1
- NormalizeImage:
scale: 1./255.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
#mix:
# - MixupOperator:
# alpha: 0.2
VALID:
batch_size: 64
num_workers: 1
file_list: "./dataset/flowers102/val_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- ResizeImage:
resize_short: 256
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
mode: 'train'
ARCHITECTURE:
name: 'MobileNetV3_large_x1_0'
pretrained_model: "./pretrained/MobileNetV3_large_x1_0_pretrained"
model_save_dir: "./output/"
classes_num: 102
total_images: 1020
save_interval: 1
validate: True
valid_interval: 1
epochs: 20
topk: 5
image_shape: [3, 224, 224]
LEARNING_RATE:
function: 'Cosine'
params:
lr: 0.00375
OPTIMIZER:
function: 'Momentum'
params:
momentum: 0.9
regularizer:
function: 'L2'
factor: 0.000001
TRAIN:
batch_size: 32
num_workers: 4
file_list: "./dataset/flowers102/train_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- RandCropImage:
size: 224
- RandFlipImage:
flip_code: 1
- NormalizeImage:
scale: 1./255.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
VALID:
batch_size: 20
num_workers: 4
file_list: "./dataset/flowers102/val_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- ResizeImage:
resize_short: 256
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
mode: 'train'
ARCHITECTURE:
name: 'ResNet50_vd_distill_MobileNetV3_large_x1_0'
pretrained_model:
- "./pretrain/flowers102_R50_vd_final/ppcls"
- "./pretrained/MobileNetV3_large_x1_0_pretrained/"
model_save_dir: "./output/"
classes_num: 102
total_images: 7169
save_interval: 1
validate: True
valid_interval: 1
epochs: 20
topk: 5
image_shape: [3, 224, 224]
use_distillation: True
LEARNING_RATE:
function: 'Cosine'
params:
lr: 0.0125
OPTIMIZER:
function: 'Momentum'
params:
momentum: 0.9
regularizer:
function: 'L2'
factor: 0.00007
TRAIN:
batch_size: 32
num_workers: 4
file_list: "./dataset/flowers102/train_test_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- RandCropImage:
size: 224
- RandFlipImage:
flip_code: 1
- NormalizeImage:
scale: 1./255.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
VALID:
batch_size: 20
num_workers: 4
file_list: "./dataset/flowers102/val_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- ResizeImage:
resize_short: 256
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
mode: 'train'
ARCHITECTURE:
name: 'ResNet50_vd'
pretrained_model: ""
model_save_dir: "./output/"
classes_num: 102
total_images: 1020
save_interval: 1
validate: True
valid_interval: 1
epochs: 20
topk: 5
image_shape: [3, 224, 224]
LEARNING_RATE:
function: 'Cosine'
params:
lr: 0.0125
OPTIMIZER:
function: 'Momentum'
params:
momentum: 0.9
regularizer:
function: 'L2'
factor: 0.00001
TRAIN:
batch_size: 32
num_workers: 4
file_list: "./dataset/flowers102/train_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- RandCropImage:
size: 224
- RandFlipImage:
flip_code: 1
- NormalizeImage:
scale: 1./255.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
VALID:
batch_size: 20
num_workers: 4
file_list: "./dataset/flowers102/val_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- ResizeImage:
resize_short: 256
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
mode: 'train'
ARCHITECTURE:
name: 'ResNet50_vd'
pretrained_model: "./pretrained/ResNet50_vd_pretrained"
model_save_dir: "./output/"
classes_num: 102
total_images: 1020
save_interval: 1
validate: True
valid_interval: 1
epochs: 20
topk: 5
image_shape: [3, 224, 224]
LEARNING_RATE:
function: 'Cosine'
params:
lr: 0.00375
OPTIMIZER:
function: 'Momentum'
params:
momentum: 0.9
regularizer:
function: 'L2'
factor: 0.000001
TRAIN:
batch_size: 32
num_workers: 4
file_list: "./dataset/flowers102/train_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- RandCropImage:
size: 224
- RandFlipImage:
flip_code: 1
- NormalizeImage:
scale: 1./255.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
VALID:
batch_size: 20
num_workers: 4
file_list: "./dataset/flowers102/val_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- ResizeImage:
resize_short: 256
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
......@@ -10,12 +10,10 @@ total_images: 1020
save_interval: 1
validate: True
valid_interval: 1
epochs: 40
epochs: 20
topk: 5
image_shape: [3, 224, 224]
ls_epsilon: 0.1
LEARNING_RATE:
function: 'Cosine'
params:
......@@ -52,7 +50,7 @@ TRAIN:
- ToCHWImage:
VALID:
batch_size: 32
batch_size: 20
num_workers: 4
file_list: "./dataset/flowers102/val_list.txt"
data_dir: "./dataset/flowers102/"
......
mode: 'train'
ARCHITECTURE:
name: 'ResNet50_vd'
params:
lr_mult_list: [0.1, 0.1, 0.2, 0.2, 0.3]
pretrained_model: "./pretrained/ResNet50_vd_ssld_pretrained"
model_save_dir: "./output/"
classes_num: 102
total_images: 1020
save_interval: 1
validate: True
valid_interval: 1
epochs: 20
topk: 5
image_shape: [3, 224, 224]
LEARNING_RATE:
function: 'Cosine'
params:
lr: 0.00375
OPTIMIZER:
function: 'Momentum'
params:
momentum: 0.9
regularizer:
function: 'L2'
factor: 0.000001
TRAIN:
batch_size: 32
num_workers: 4
file_list: "./dataset/flowers102/train_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- RandCropImage:
size: 224
- RandFlipImage:
flip_code: 1
- NormalizeImage:
scale: 1./255.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- RandomErasing:
EPSILON: 0.5
- ToCHWImage:
VALID:
batch_size: 20
num_workers: 4
file_list: "./dataset/flowers102/val_list.txt"
data_dir: "./dataset/flowers102/"
shuffle_seed: 0
transforms:
- DecodeImage:
to_rgb: True
to_np: False
channel_first: False
- ResizeImage:
resize_short: 256
- CropImage:
size: 224
- NormalizeImage:
scale: 1.0/255.0
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
order: ''
- ToCHWImage:
set -e
if [ "x${IMAGENET_USERNAME}" == x -o "x${IMAGENET_ACCESS_KEY}" == x ];then
echo "Please create an account on image-net.org."
echo "It will provide you a pair of username and accesskey to download imagenet data."
read -p "Username: " IMAGENET_USERNAME
read -p "Accesskey: " IMAGENET_ACCESS_KEY
fi
root_url=http://www.image-net.org/challenges/LSVRC/2012/nnoupb
valid_tar=ILSVRC2012_img_val.tar
train_tar=ILSVRC2012_img_train.tar
train_folder=train/
valid_folder=val/
echo "Download imagenet training data..."
mkdir -p ${train_folder}
wget -nd -c ${root_url}/${train_tar}
tar xf ${train_tar} -C ${train_folder}
cd ${train_folder}
for x in `ls *.tar`
do
filename=`basename $x .tar`
mkdir -p $filename
tar -xf $x -C $filename
rm -rf $x
done
cd -
echo "Download imagenet validation data..."
mkdir -p ${valid_folder}
wget -nd -c ${root_url}/${valid_tar}
tar xf ${valid_tar} -C ${valid_folder}
echo "Download imagenet label file: val_list.txt & train_list.txt"
label_file=ImageNet_label.tgz
label_url=http://paddle-imagenet-models.bj.bcebos.com/${label_file}
wget -nd -c ${label_url}
tar zxf ${label_file}
"""
.mat files data format
imagelabel.mat
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
"""
import scipy.io
import numpy as np
import os
import sys
data_path = sys.argv[1]
imagelabels_path = './imagelabels.mat'
setid_path = './setid.mat'
labels = scipy.io.loadmat(imagelabels_path)
labels = np.array(labels['labels'][0])
setid = scipy.io.loadmat(setid_path)
d = {}
d['train'] = np.array(setid['trnid'][0])
d['valid'] = np.array(setid['valid'][0])
d['test'] = np.array(setid['tstid'][0])
for id in d[sys.argv[2]]:
message = str(data_path) + "/image_" + str(id).zfill(5) + ".jpg " + str(labels[id - 1] - 1)
print(message)
# 训练技巧
正在持续更新中......
## 1.优化器的选择
自深度学习发展以来,就有很多关于优化器的研究者工作,优化器的目的是为了让损失函数尽可能的小,从而找到合适的参数来完成某项任务。目前业界主要用到的优化器有SGD、RMSProp、Adam、AdaDelt等,其中由于带momentum的SGD优化器广泛应用于学术界和工业界,所以我们发布的模型也大都使用该优化器来实现损失函数的梯度下降。带momentum的SGD优化器有两个劣势,其一是收敛速度慢,其二是初始学习率的设置需要依靠大量的经验,然而如果初始学习率设置得当并且迭代轮数充足,该优化器也会在众多的优化器中脱颖而出,使得其在验证集上获得更高的准确率。一些自适应学习率的优化器如Adam、RMSProp等,收敛速度往往比较快,但是最终的收敛精度会稍差一些。如果追求更快的收敛速度,我们推荐使用这些自适应学习率的优化器,如果追求更高的收敛精度,我们推荐使用带momentum的SGD优化器。
## 2.学习率以及学习率下降策略的选择
学习率的选择往往和优化器以及数据和任务有关系。这里主要介绍以momentum+SGD作为优化器训练ImageNet-1k的学习率以及学习率下降的选择。
### 学习率的概念:
学习率是通过损失函数的梯度调整网络权重的超参数的速度。学习率越低,损失函数的变化速度就越慢。虽然使用低学习率可以确保不会错过任何局部极小值,但也意味着将花费更长的时间来进行收敛,特别是在被困在高原区域的情况下。
### 学习率下降策略:
在整个训练过程中,我们不能使用同样的学习率来更新权重,否则无法到达最优点,所以需要在训练过程中调整学习率的大小。在训练初始阶段,由于权重处于随机初始化的状态,损失函数相对容易进行梯度下降,所以可以设置一个较大的学习率。在训练后期,由于权重参数已经接近最优值,较大的学习率无法进一步寻找最优值,所以需要设置一个较小的学习率。在训练整个过程中,很多研究者使用的学习率下降方式是piecewise_decay,即阶梯式下降学习率,如在ResNet50标准的训练中,我们设置的初始学习率是0.1,每30epoch学习率下降到原来的1/10,一共迭代120epoch。除了piecewise_decay,很多研究者也提出了学习率的其他下降方式,如polynomial_decay(多项式下降)、exponential_decay(指数下降),cosine_decay(余弦下降)等,其中cosine_decay无需调整超参数,鲁棒性也比较高,所以成为现在提高模型精度首选的学习率下降方式。Cosine_decay和piecewise_decay的学习率变化曲线如下图所示,容易观察到,在整个训练过程中,cosine_decay都保持着较大的学习率,所以其收敛较为缓慢,但是最终的收敛效果较peicewise_decay更好一些。
<div align="center">
<img
src="../../images/models/lr_decay.jpeg" width="500">
</div>
另外,从图中我们也可以看到,cosine_decay里学习率小的轮数较少,这样会影响到最终的精度,所以为了使得cosine_decay发挥更好的效果,建议迭代更多的轮数,如200轮。
### warmup策略
如果使用较大的batch_size训练神经网络时,我们建议您使用warmup策略。Warmup策略顾名思义就是让学习率先预热一下,在训练初期我们不直接使用最大的学习率,而是用一个逐渐增大的学习率去训练网络,当学习率增大到最高点时,再使用学习率下降策略中提到的学习率下降方式衰减学习率的值。实验表明,在batch_size较大时,warmup可以稳定提升模型的精度。在训练MobileNetV3等batch_size较大的实验中,我们默认将warmup中的epoch设置为5,即先用5epoch将学习率从0增加到最大值,再去做相应的学习率衰减。
## 3.batch_size的选择
batch_size是训练神经网络中的一个重要的超参数,该值决定了一次将多少数据送入神经网络参与训练。在论文[1]中,作者通过实验发现,当batch_size的值与学习率的值呈线性关系时,收敛精度几乎不受影响。在训练ImageNet数据时,大部分的神经网络选择的初始学习率为0.1,batch_size是256,所以根据实际的模型大小和显存情况,可以将学习率设置为0.1*k,batch_size设置为256*k。
## 4.weight_decay的选择
过拟合是机器学习中常见的一个名词,简单理解即为模型在训练数据上表现很好,但在测试数据上表现较差,在卷积神经网络中,同样存在过拟合的问题,为了避免过拟合,很多正则方式被提出,其中,weight_decay是其中一个广泛使用的避免过拟合的方式。Weight_decay等价于在最终的损失函数后添加L2正则化,L2正则化使得网络的权重倾向于选择更小的值,最终整个网络中的参数值更趋向于0,模型的泛化性能相应提高。在各大深度学习框架的实现中,该值表达的含义是L2正则前的系数,在paddle框架中,该值的名称是l2_decay,所以以下都称其为l2_decay。该系数越大,表示加入的正则越强,模型越趋于欠拟合状态。在训练ImageNet的任务中,大多数的网络将该参数值设置为1e-4,在一些小的网络如MobileNet系列网络中,为了避免网络欠拟合,该值设置为1e-5~4e-5之间。当然,该值的设置也和具体的数据集有关系,当任务的数据集较大时,网络本身趋向于欠拟合状态,可以将该值适当减小,当任务的数据集较小时,网络本身趋向于过拟合状态,可以将该值适当增大。下表展示了MobileNetV1_x0_25在ImageNet-1k上使用不同l2_decay的精度情况。由于MobileNetV1_x0_25是一个比较小的网络,所以l2_decay过大会使网络趋向于欠拟合状态,所以在该网络中,相对1e-4,3e-5是更好的选择。
| 模型 | L2_decay | Train acc1/acc5 | Test acc1/acc5 |
|:--:|:--:|:--:|:--:|
| MobileNetV1_x0_25 | 1e-4 | 43.79%/67.61% | 50.41%/74.70% |
| MobileNetV1_x0_25 | 3e-5 | 47.38%/70.83% | 51.45%/75.45% |
另外,该值的设置也和训练过程中是否使用其他正则化有关系。如果训练过程中的数据预处理比较复杂,相当于训练任务变的更难,可以将该值适当减小,下表展示了在ImageNet-1k上,ResNet50在使用randaugment预处理方式后使用不同l2_decay的精度。容易观察到,在任务变难后,使用更小的l2_decay有助于模型精度的提升。
| 模型 | L2_decay | Train acc1/acc5 | Test acc1/acc5 |
|:--:|:--:|:--:|:--:|
| ResNet50 | 1e-4 | 75.13%/90.42% | 77.65%/93.79% |
| ResNet50 | 7e-5 | 75.56%/90.55% | 78.04%/93.74% |
综上所述,l2_decay可以根据具体的任务和模型去做相应的调整,通常简单的任务或者较大的模型,推荐使用较大的l2_decay,复杂的任务或者较小的模型,推荐使用较小的l2_decay。
## 5.label_smoothing的选择
Label_smoothing是深度学习中的一种正则化方法,其全称是 Label Smoothing Regularization(LSR),即标签平滑正则化。在传统的分类任务计算损失函数时,是将真实的one hot标签与神经网络的输出做相应的交叉熵计算,而label_smoothing是将真实的one hot标签做一个标签平滑的处理,使得网络学习的标签不再是一个hard label,而是一个有概率值的soft label,其中在类别对应的位置的概率最大,其他位置概率是一个非常小的数。具体的计算方式参见论文[2]。在label_smoothing里,有一个epsilon的参数值,该值描述了将标签软化的程度,该值越大,经过label smoothing后的标签向量的标签概率值越小,标签越平滑,反之,标签越趋向于hard label,在训练ImageNet-1k的实验里通常将该值设置为0.1。
在训练ImageNet-1k的实验中,我们发现,ResNet50大小级别及其以上的模型在使用label_smooting后,精度有稳定的提升。下表展示了ResNet50_vd在使用label_smoothing前后的精度指标。
| 模型 | Use_label_smoothing | Test acc1 |
|:--:|:--:|:--:|
| ResNet50_vd | 0 | 77.9% |
| ResNet50_vd | 1 | 78.4% |
同时,由于label_smoohing相当于一种正则方式,在相对较小的模型上,精度提升不明显甚至会有所下降,下表展示了ResNet18在ImageNet-1k上使用label_smoothing前后的精度指标。可以明显看到,在使用label_smoothing后,精度有所下降。
| 模型 | Use_label_smoohing | Train acc1/acc5 | Test acc1/acc5 |
|:--:|:--:|:--:|:--:|
| ResNet18 | 0 | 69.81%/87.70% | 70.98%/89.92% |
| ResNet18 | 1 | 68.00%/86.56% | 70.81%/89.89% |
综上所述,较大的模型使用label_smoohing可以有效提升模型的精度,较小的模型使用label_smoohing可能会降低模型的精度,所以在决定是否使用label_smoohing前,需要评估模型的大小和任务的难易程度。
## 6.针对更小的模型如何进行图片的crop与拉伸变换
在ImageNet-1k数据的标准预处理中,random_crop函数中定义了scale和ratio两个值,两个值分别确定了图片crop的大小和图片的拉伸程度,其中scale的默认取值范围是0.08-1(lower_scale-upper_scale),ratio的默认取值范围是3/4-4/3(lower_ratio-upper_ratio)。在非常小的网络训练中,此类数据增强会使得网络欠拟合,导致精度有所下降。为了提升网络的精度,可以使其数据增强变的更弱,即增大图片的crop区域或者减弱图片的拉伸变换程度。我们可以分别通过增大lower_scale的值或缩小lower_ratio与upper_scale的差距来实现更弱的图片变换。下表列出了使用不同lower_scale训练MobileNetV2_x0_25的精度,可以看到,增大图片的crop区域面积后训练精度和验证精度均有提升。
| 模型 | Scale取值范围 | Train_acc1/acc5 | Test_acc1/acc5 |
|:--:|:--:|:--:|:--:|
| MobileNetV2_x0_25 | [0.08,1] | 50.36%/72.98% | 52.35%/75.65% |
| MobileNetV2_x0_25 | [0.2,1] | 54.39%/77.08% | 53.18%/76.14% |
## 7.使用数据增广方式提升精度
一般来说,数据集的规模对性能影响至关重要,但是图片的标注往往比较昂贵,所以有标注的图片数量往往比较稀少,在这种情况下,数据的增广尤为重要。在训练ImageNet-1k的标准数据增广中,主要使用了random_crop与random_flip两种数据增广方式,然而,近些年,越来越多的数据增广方式被提出,如cutout、mixup、cutmix、AutoAugment等。实验表明,这些数据的增广方式可以有效提升模型的精度,下表列出了ResNet50在8种不同的数据增广方式的表现,可以看出,相比baseline,所有的数据增广方式均有收益,其中cutmix是目前最有效的数据增广。更多数据增广的介绍请参考[**数据增广章节**](https://paddleclas.readthedocs.io/zh_CN/latest/advanced_tutorials/image_augmentation/ImageAugment.html)
| 模型 | 数据增广方式 | Test top-1 |
|:--:|:--:|:--:|
| ResNet50 | 标准变换 | 77.31% |
| ResNet50 | Auto-Augment | 77.95% |
| ResNet50 | Mixup | 78.28% |
| ResNet50 | Cutmix | 78.39% |
| ResNet50 | Cutout | 78.01% |
| ResNet50 | Gridmask | 77.85% |
| ResNet50 | Random-Augment | 77.70% |
| ResNet50 | Random-Erasing | 77.91% |
| ResNet50 | Hide-and-Seek | 77.43% |
## 8. 通过train_acc和test_acc确定调整策略
在训练网络的过程中,通常会打印每一个epoch的训练集准确率和验证集准确率,二者刻画了该模型在两个数据集上的表现。通常来说,训练集的准确率比验证集准确率微高或者二者相当是比较不错的状态。如果发现训练集的准确率比验证集高很多,说明在这个任务上已经过拟合,需要在训练过程中加入更多的正则,如增大l2_decay的值,加入更多的数据增广策略,加入label_smoothing策略等;如果发现训练集的准确率比验证集低一些,说明在这个任务上可能欠拟合,需要在训练过程中减弱正则效果,如减小l2_decay的值,减少数据增广方式,增大图片crop区域面积,减弱图片拉伸变换,去除label_smoothing等。
## 9.如何通过已有的预训练模型提升自己的数据集的精度
在现阶段计算机视觉领域中,加载预训练模型来训练自己的任务已成为普遍的做法,相比从随机初始化开始训练,加载预训练模型往往可以提升特定任务的精度。一般来说,业界广泛使用的预训练模型是通过训练128万张图片1000类的ImageNet-1k数据集得到的,该预训练模型的fc层权重是是一个k\*1000的矩阵,其中k是fc层以前的神经元数,在加载预训练权重时,无需加载fc层的权重。在学习率方面,如果您的任务训练的数据集特别小(如小于1千张),我们建议你使用较小的初始学习率,如0.001(batch_size:256,下同),以免较大的学习率破坏预训练权重。如果您的训练数据集规模相对较大(大于10万),我们建议你尝试更大的初始学习率,如0.01或者更大。
## 参考文献
[1]P. Goyal, P. Dolla ́r, R. B. Girshick, P. Noordhuis, L. Wesolowski, A. Kyrola, A. Tulloch, Y. Jia, and K. He. Accurate, large minibatch SGD: training imagenet in 1 hour. CoRR, abs/1706.02677, 2017.
[2]C.Szegedy,V.Vanhoucke,S.Ioffe,J.Shlens,andZ.Wojna. Rethinking the inception architecture for computer vision. CoRR, abs/1512.00567, 2015
# 数据说明
---
## 1.简介
本文档介绍ImageNet1k和Flower102数据准备过程。
以及PaddleClas提供了丰富的[预训练模型](../models/models_intro.md)
## 2.数据集准备
数据集 | 训练集大小 | 测试集大小 | 类别数 | 备注|
:------:|:---------------:|:---------------------:|:-----------:|:-----------:
[Flower102](https://www.robots.ox.ac.uk/~vgg/data/flowers/102/)|1k | 6k | 102 |
[ImageNet1k](http://www.image-net.org/challenges/LSVRC/2012/)|1.2M| 50k | 1000 |
数据格式
按照如下结构组织数据,其中train_list.txt 和val_list.txt的格式形如
```
#每一行采用"空格"分隔图像路径与标注
ILSVRC2012_val_00000001.JPEG 65
...
```
### ImageNet1k
从官方下载数据后,按如下组织数据
```bash
PaddleClas/dataset/imagenet/
|_ train/
| |_ n01440764
| | |_ n01440764_10026.JPEG
| | |_ ...
| |_ ...
| |
| |_ n15075141
| |_ ...
| |_ n15075141_9993.JPEG
|_ val/
| |_ ILSVRC2012_val_00000001.JPEG
| |_ ...
| |_ ILSVRC2012_val_00050000.JPEG
|_ train_list.txt
|_ val_list.txt
```
### Flower
[VGG官方网站](https://www.robots.ox.ac.uk/~vgg/data/flowers/102/)下载后的数据,解压后包括
jpg/
setid.mat
imagelabels.mat
将以上文件放置在PaddleClas/dataset/flower102/下
通过运行generate_flower_list.py生成train_list.txt和val_list.txt
```bash
python generate_flower_list.py jpg train > train_list.txt
python generate_flower_list.py jpg valid > val_list.txt
```
按照如下结构组织数据:
```bash
PaddleClas/dataset/flower102/
|_ jpg/
| |_ image_03601.jpg
| |_ ...
| |_ image_02355.jpg
|_ train_list.txt
|_ val_list.txt
```
## 3.下载预训练模型
通过tools/download.py下载所需要的预训练模型。
```bash
python tools/download.py -a ResNet50_vd -p ./pretrained -d True
```
参数说明:
+ `architecture`(简写 a):模型结构
+ `path`(简写 p):下载路径
+ `decompress` (简写 d):是否解压
# 开始使用
---
请事先参考[安装指南](install.md)配置运行环境
有关模型库的基本信息请参考[README](https://github.com/PaddlePaddle/PaddleClas/blob/master/README.md)
## 一、设置环境变量
......@@ -15,15 +16,17 @@ export PYTHONPATH=path_to_PaddleClas:$PYTHONPATH
PaddleClas 提供模型训练与评估脚本:tools/train.py和tools/eval.py
### 2.1 模型训练
以flower102数据为例按如下方式启动模型训练,flower数据集准备请参考[数据集准备](./data.md)
```bash
# PaddleClas通过launch方式启动多卡多进程训练
# 通过设置FLAGS_selected_gpus 指定GPU运行卡号
python -m paddle.distributed.launch \
--selected_gpus="0,1,2,3" \
--log_dir=log_ResNet50 \
--log_dir=log_ResNet50_vd \
tools/train.py \
-c ./configs/ResNet/ResNet50.yaml
-c ./configs/flower.yaml
```
- 输出日志示例如下:
......@@ -32,14 +35,14 @@ python -m paddle.distributed.launch \
epoch:0 train step:13 loss:7.9561 top1:0.0156 top5:0.1094 lr:0.100000 elapse:0.193
```
可以通过添加-o参数来更新配置
可以通过添加-o参数来更新配置
```bash
python -m paddle.distributed.launch \
--selected_gpus="0,1,2,3" \
--log_dir=log_ResNet50_vd \
tools/train.py \
-c ./configs/ResNet/ResNet50_vd.yaml \
-c ./configs/flower.yaml \
-o use_mix=1
```
......@@ -54,18 +57,40 @@ epoch:0 train step:522 loss:1.6330 lr:0.100000 elapse:0.210
### 2.3 模型微调
您可以通过如下命令进行模型微调,通过指定--pretrained_model参数加载预训练模型
以ResNet50_vd和ResNet50_vd_ssld预训练模型对flower102数据集进行微调。
ResNet50_vd: 在ImageNet1k数据集上训练 top1 acc:79.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,1,2,3" \
--log_dir=log_ResNet50_vd \
train.py \
-c ../configs/ResNet/ResNet50_vd.yaml \
-o pretrained_model= 预训练模型路径\
--selected_gpus="0" \
tools/train.py \
-c ./configs/finetune/ResNet50_vd_finetune.yaml
-o pretrained_model=path_to_ResNet50_vd_pretrained_models
```
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=path_to_ResNet50_vd_ssld_pretrained_models
```
在使用ResNet50_vd预训练模型对flower102数据进行模型微调后,top1 acc 达到 92.71%。
在使用ResNet50_vd_ssld预训练模型对flower102数据进行模型微调后,top1 acc 达到94.96%。
### 2.2 模型评估
```bash
......@@ -79,7 +104,7 @@ python tools/eval.py \
## 三、模型推理
PaddlePaddle提供三种方式进行预测推理,接下来介绍如何用预测引擎进行推理:
首先,对训练好的模型进行转换
首先,对训练好的模型进行转换
```bash
python tools/export_model.py \
-model=模型名字 \
......@@ -87,7 +112,7 @@ python tools/export_model.py \
-output_path=预测模型保存路径
```
之后,通过预测引擎进行推理
之后,通过预测引擎进行推理
```bash
python tools/infer/predict.py \
-m model文件路径 \
......@@ -96,4 +121,4 @@ python tools/infer/predict.py \
--use_gpu=1 \
--use_tensorrt=True
```
更多使用方法和推理方式请参考[分类预测框架](../extension/paddle_inference.md)
更多使用方法和推理方式请参考[分类预测框架](../extension/paddle_inference.md)
......@@ -7,3 +7,4 @@
install.md
getting_started.md
config.md
data.md
......@@ -4,33 +4,43 @@
## 1.简介
本章将介绍如何安装PaddleClas及其依赖项,准备ImageNet1k图像分类数据集和下载预训练模型。
本章将介绍如何安装PaddleClas及其依赖项.
有关模型库的基本信息请参考[README](https://github.com/PaddlePaddle/PaddleClas/blob/master/README.md)
## 2.安装PaddlePaddle
运行PaddleClas需要PaddlePaddle Fluid v1.7或更高版本。请按照[安装文档](http://www.paddlepaddle.org.cn/install/quick)中的说明进行操作。
运行PaddleClas需要PaddlePaddle Fluid v1.7或更高版本。
使用以下命令进行验证。
pip安装最新GPU版本PaddlePaddle
```bash
pip install paddlepaddle-gpu --upgrade
```
# 在您的Python解释器中确认PaddlePaddle安装成功
>>> import paddle.fluid as fluid
>>> fluid.install_check.run_check()
# 确认PaddlePaddle版本
python -c "import paddle; print(paddle.__version__)"
或是从源码安装PaddlePaddle,具体参照[安装文档](http://www.paddlepaddle.org.cn/install/quick)中的说明进行操作。
使用以下命令验证
```python
import paddle.fluid as fluid
fluid.install_check.run_check()
```
查看PaddlePaddle版本
```bash
python -c "import paddle; print(paddle.__version__)"
```
注意:
- 从源码编译的PaddlePaddle版本号为0.0.0,请确保使用了Fluid v1.7之后的源码编译。
- PaddleClas基于PaddlePaddle高性能的分布式训练能力,若您从源码编译,请确保打开编译选项,**WITH_DISTRIBUTE=ON**
- PaddleClas基于PaddlePaddle高性能的分布式训练能力,若您从源码编译,请确保打开编译选项,**WITH_DISTRIBUTE=ON**。具体编译选项参考[编译选项表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/install/Tables.html#id3)
**环境需求:**
**运行环境需求:**
- Python2(官方已不提供更新维护)或Python3 (windows系统仅支持Python3)
- CUDA >= 8.0
- CUDA >= 9.0
- cuDNN >= 5.0
- nccl >= 2.1.2
......@@ -53,40 +63,12 @@ pip install --upgrade -r requirements.txt
```
## 4.下载ImageNet1K图像分类数据集
## 4.数据集和预训练模型
PaddleClas默认支持ImageNet1000分类任务。
在Linux系统下通过如下方式进行数据准备:
```
cd dataset/ILSVRC2012/
sh download_imagenet2012.sh
```
```download_imagenet2012.sh```脚本中,通过下面三步来准备数据:
PaddleClas加载PaddleClas/dataset/中数据进行训练,请参照[数据文档](./data.md)进行准备。
PaddleClas提供丰富的预训练模型,请参照[数据文档](./data.md)进行准备。
**步骤一:** 首先在```image-net.org```网站上完成注册,用于获得一对```Username``````AccessKey```
**步骤二:** 从ImageNet官网下载ImageNet-2012的图像数据。训练以及验证数据集会分别被下载到"train" 和 "val" 目录中。注意,ImageNet数据的大小超过140GB,下载非常耗时;已经自行下载ImageNet的用户可以直接将数据按"train" 和 "val" 目录放到```dataset/ILSVRC2012```
## 5.开始使用
**步骤三:** 下载训练与验证集合对应的标签文件。
* train_list.txt: ImageNet-2012训练集合的标签文件,每一行采用"空格"分隔图像路径与标注,例如:
```
train/n02483708/n02483708_2436.jpeg 369
```
* val_list.txt: ImageNet-2012验证集合的标签文件,每一行采用"空格"分隔图像路径与标注,例如:
```
val/ILSVRC2012_val_00000001.jpeg 65
```
**Windows系统下请用户自行下载ImageNet数据,[label下载链接](http://paddle-imagenet-models.bj.bcebos.com/ImageNet_label.tgz)**
## 5.下载预训练模型
PaddleClas 提供了丰富的预训练模型,支持的模型列表请参考[模型库](../models/models_intro.md)
通过tools/download.py可以下载所需要的预训练模型。
```bash
python tools/download.py -a ResNet50_vd -p ./pretrained -d True
```
请参照[开始使用](./getting_started.md)文档
......@@ -44,4 +44,4 @@ from .darts_gs import DARTS_GS_6M, DARTS_GS_4M
from .resnet_acnet import ResNet18_ACNet, ResNet34_ACNet, ResNet50_ACNet, ResNet101_ACNet, ResNet152_ACNet
# distillation model
from .distillation_models import ResNet50_vd_distill_MobileNetV3_x1_0, ResNeXt101_32x16d_wsl_distill_ResNet50_vd
from .distillation_models import ResNet50_vd_distill_MobileNetV3_large_x1_0, ResNeXt101_32x16d_wsl_distill_ResNet50_vd
......@@ -27,12 +27,12 @@ from .mobilenet_v3 import MobileNetV3_large_x1_0
from .resnext101_wsl import ResNeXt101_32x16d_wsl
__all__ = [
'ResNet50_vd_distill_MobileNetV3_x1_0',
'ResNet50_vd_distill_MobileNetV3_large_x1_0',
'ResNeXt101_32x16d_wsl_distill_ResNet50_vd'
]
class ResNet50_vd_distill_MobileNetV3_x1_0():
class ResNet50_vd_distill_MobileNetV3_large_x1_0():
def net(self, input, class_dim=1000):
# student
student = MobileNetV3_large_x1_0()
......
......@@ -67,7 +67,7 @@ def check_architecture(architecture):
similar_names = similar_architectures(architecture["name"],
get_architectures())
model_list = ', '.join(similar_names)
err = "{} is not exist! Maybe you want: [{}]" \
err = "Architecture [{}] is not exist! Maybe you want: [{}]" \
"".format(architecture["name"], model_list)
try:
assert architecture["name"] in similar_names
......
......@@ -118,7 +118,10 @@ def init_model(config, program, exe):
pretrained_model = config.get('pretrained_model')
if pretrained_model:
load_params(exe, program, pretrained_model)
if not isinstance(pretrained_model, list):
pretrained_model = [pretrained_model]
for pretrain in pretrained_model:
load_params(exe, program, pretrain)
logger.info("Finish initing model from {}".format(pretrained_model))
......
......@@ -71,8 +71,9 @@ def main(args):
valid_reader = Reader(config, 'valid')()
valid_dataloader.set_sample_list_generator(valid_reader, place)
compiled_valid_prog = program.compile(config, valid_prog)
#compiled_valid_prog = program.compile(config, valid_prog)
compiled_valid_prog = valid_prog
program.run(valid_dataloader, exe, compiled_valid_prog, valid_fetchs, 0,
'valid')
......
export PYTHONPATH=$PWD:$PYTHONPATH
python -m paddle.distributed.launch \
--selected_gpus="0" \
tools/eval.py \
-c ./configs/eval.yaml
......@@ -389,3 +389,4 @@ def run(dataloader, exe, program, fetchs, epoch=0, mode='train'):
fetchs_str = ''.join([str(m) for m in metric_list] + [str(batch_time)])
logger.info("[epoch:%3d][%s][step:%4d]%s" %
(epoch, mode, idx, fetchs_str))
logger.info("END [epoch:%3d][%s]%s"%(epoch, mode, fetchs_str))
......@@ -4,6 +4,5 @@ export PYTHONPATH=$PWD:$PYTHONPATH
python -m paddle.distributed.launch \
--selected_gpus="0,1,2,3" \
--log_dir=log_ResNet50 \
tools/train.py \
-c ./configs/ResNet/ResNet50.yaml
......@@ -82,8 +82,8 @@ def main(args):
if config.validate:
valid_reader = Reader(config, 'valid')()
valid_dataloader.set_sample_list_generator(valid_reader, place)
compiled_valid_prog = program.compile(config, valid_prog)
#compiled_valid_prog = program.compile(config, valid_prog)
compiled_valid_prog = valid_prog
compiled_train_prog = fleet.main_program
for epoch_id in range(config.epochs):
# 1. train with train dataset
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册