前情提要

  通过之前教程中的学习,相信大家对于如何搭建一个分类网络已经清晰了。那么我们不禁会想,有没有更快速的尝试模型及技巧的方法呢?因为我们在上一次课程中使用的代码都需要自己进行开发,自己写需要很多的精力。PaddleClas作为飞桨的一个图像分类套件,已经为大家把所有的内容都写好了,只需要大家选择模型、并适配自己的数据集即可。

基于飞桨图像分类套件PaddleClas的柠檬分类竞赛实战

PaddleClas 是什么?

  PaddleClas是飞桨为工业界和学术界所准备的一个图像分类任务的工具集,助力使用者训练出更好的视觉模型和应用落地。PaddleClas提供了基于图像分类的模型训练、评估、预测、部署全流程的服务,方便大家更加高效地学习图像分类。

下面将从PaddleClas模型库概览、初级使用、高级使用几个方面介绍PaddleClas实践方法:

  1. PaddleClas模型库概览:概要介绍PaddleClas有哪些分类网络结构。
  2. PaddleClas柠檬竞赛实战:重点介绍数据增广方法。

PaddleClas模型库概览

  图像分类模型有大有小,其应用场景各不相同,在云端或者服务器端应用时,一般情况下算力是足够的,更倾向于应用高精度的模型,我们称之为服务器端模型;在手机、嵌入式等端侧设备中应用时,受限于设备的算力和内存,则对模型的速度和大小有较高的要求,我们称之为移动端模型(端侧轻量化模型)。PaddleClas同时提供了服务器端模型与端侧轻量化模型来支撑不同的应用场景。

  这里我们使用MobileNetV2模型,因为它在预测速度和性能上都具有很大的优势,而且符合我们此次竞赛实战的要求,用户可以根据预测耗时的要求选择不同的网络。此外,PaddleClas也开源了预训练模型,我们可以基于此在自己的数据集上进行微调,提升效果。

更多模型详细介绍和模型训练技巧,可查看PaddleClas模型库文档以及PaddleClas分类套件

前置条件(安装)

  1. 安装Python3.5或更高版本版本。
  2. 安装PaddlePaddle 1.7或更高版本,具体安装方法请参见快速安装。由于图像分类模型计算开销大,推荐在GPU版本的PaddlePaddle下使用PaddleClas。
  3. 下载PaddleClas的代码库。
cd path_to_clone_PaddleClas以下二者任选其一
git clone https://github.com/PaddlePaddle/PaddleClas.git
git clonehttps://gitee.com/paddlepaddle/PaddleClas.git
  1. 安装Python依赖库。Python依赖库在requirements.txt中给出。(本地)
pip install --upgrade -r requirements.txt
  1. 设置PYTHONPATH环境变量(本地)
export PYTHONPATH=path_to_PaddleClas:$PYTHONPATH

PaddleClas初级使用

PaddleClas快速上手

一、准备数据集

PaddleClas数据准备文档提供了ImageNet1k数据集以及flowers102数据集的准备过程。当然,如果大家希望使用自己的数据集,则需要至少准备以下两份文件。

  • 训练集图像,以图像文件形式保存。
  • 训练集标签文件,以文本形式保存,每一行的文件都包含文件名以及图像标签,以空格隔开。下面给出一个示例。
ILSVRC2012_val_00000001.JPEG 65
...

如果需要在训练的时候进行验证,则也同时需要提供验证集图像以及验证集标签文件。

以训练集配置为例,配置文件中对应如下

TRAIN: # 训练配置batch_size: 32 # 训练的batch sizenum_workers: 4 # 每个trainer(1块GPU上可以视为1个trainer)的进程数量file_list: "./dataset/flowers102/train_list.txt" # 训练集标签文件,每一行由"image_name label"组成data_dir: "./dataset/flowers102/" # 训练集的图像数据路径shuffle_seed: 0 # 数据打散的种子transforms: # 训练图像的数据预处理- DecodeImage: # 解码to_rgb: Trueto_np: Falsechannel_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: # 通道转换

其中file_list即训练数据集的标签文件,data_dir是图像所在的文件夹。

!cd data/data71799/ && unzip -q lemon_lesson.zip
!cd data/data71799/lemon_lesson && unzip -q train_images.zip
!cd data/data71799/lemon_lesson && unzip -q test_images.zip
import pandas as pd
import codecs
import os
from PIL import Imagedf = pd.read_csv('data/data71799/lemon_lesson/train_images.csv')all_file_dir = 'work'train_file = codecs.open(os.path.join(all_file_dir, "train_list.txt"), 'w')
eval_file = codecs.open(os.path.join(all_file_dir, "eval_list.txt"), 'w')image_path_list = df['id'].values
label_list = df['class_num'].values# 划分训练集和校验集
all_size = len(image_path_list)
train_size = int(all_size * 0.8)
train_image_path_list = image_path_list[:train_size]
train_label_list = label_list[:train_size]
val_image_path_list = image_path_list[train_size:]
val_label_list = label_list[train_size:]image_path_pre = '/home/aistudio/data/data71799/lemon_lesson/train_images'for file,label_id in zip(train_image_path_list, train_label_list):# print(file)# print(label_id)try:img = Image.open(os.path.join(image_path_pre, file))# train_file.write("{0}\0{1}\n".format(os.path.join(image_path_pre, file), label_id))train_file.write("{0}{1}{2}\n".format(file,' ', label_id))# eval_file.write("{0}\t{1}\n".format(os.path.join(image_path_pre, file), label_id))except Exception as e:pass# 存在一些文件打不开,此处需要稍作清洗# print('error!')for file,label_id in zip(val_image_path_list, val_label_list):# print(file)# print(label_id)try:img = Image.open(os.path.join(image_path_pre, file))# train_file.write("{0}\t{1}\n".format(os.path.join(image_path_pre, file), label_id))eval_file.write("{0}{1}{2}\n".format(file,' ', label_id))except Exception as e:# pass# 存在一些文件打不开,此处需要稍作清洗print('error!')train_file.close()
需要稍作清洗print('error!')train_file.close()
eval_file.close()
/opt/conda/envs/python35-paddle120-env/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 216, got 192return f(*args, **kwds)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 216, got 192return f(*args, **kwds)

三、模型训练与评估

PaddleClas 提供模型训练与评估脚本:tools/train.pytools/eval.py

3.1 模型训练

按照如下方式启动模型训练。

python tools/train.py \-c configs/quick_start/MobileNetV3_large_x1_0_finetune.yaml

输出日志示例如下:

epoch:0    train    step:13    loss:7.9561    top1:0.0156    top5:0.1094    lr:0.100000    elapse:0.193

可以通过添加-o参数来更新配置:

python tools/train.py \-c configs/quick_start/MobileNetV3_large_x1_0_finetune.yaml \-o pretrained_model="" \-o use_gpu=True

输出日志示例如下:

epoch:0    train    step:522    loss:1.6330    lr:0.100000    elapse:0.210

也可以直接修改模型对应的配置文件更新配置。

3.2 模型评估

python tools/eval.py \-c ./configs/quick_start/MobileNetV3_large_x1_0_finetune.yaml \-o pretrained_model="./output/MobileNetV3_large_x1_0/best_model/ppcls"\-o load_static_weights=False

可以更改configs/eval.yaml中的ARCHITECTURE.name字段和pretrained_model字段来配置评估模型,也可以通过-o参数更新配置。

注意: 加载预训练模型时,需要指定预训练模型的前缀,例如预训练模型参数所在的文件夹为output/ResNet50_vd/19,预训练模型参数的名称为output/ResNet50_vd/19/ppcls.pdparams,则pretrained_model参数需要指定为output/ResNet50_vd/19/ppcls,PaddleClas会自动补齐.pdparams的后缀。

四、模型推理

首先,对训练好的模型进行转换:

python tools/infer/infer.py \-i 待预测的图片文件路径 \--model MobileNetV3_large_x1_0 \--pretrained_model "./output/MobileNetV3_large_x1_0/best_model/ppcls" \--use_gpu True \--load_static_weights False

更多的参数说明可以参考https://github.com/PaddlePaddle/PaddleClas/blob/master/tools/infer/predict.py中的parse_args函数。

更多关于服务器端与端侧的预测部署方案请参考:https://www.paddlepaddle.org.cn/documentation/docs/zh/advanced_guide/inference_deployment/index_cn.html

PaddleClas高阶使用

图像增广

ImageNet1k数据集包含128W张图片,即使不加其他策略训练,一般也能获得很高的精度,而在大部分实际场景中,都无法获得这么多的数据,这也会导致训练结果很差,通过一些数据增广的方式去扩充训练样本,可以增加训练样本的丰富度,提升模型的泛化性能。PaddleClas开源了8种数据增广方案。包括图像变换类、图像裁剪类以及图像混叠类。经过实验验证,ResNet50模型在ImageNet数据集上, 与标准变换相比,采用数据增广,识别准确率最高可以提升1%。

下面这个流程图是图片预处理并被送进网络训练的一个过程,需要经过解码、随机裁剪、水平翻转、归一化、通道转换以及组batch,最终训练的过程。

  1. 图像变换类:图像变换类是在随机裁剪与翻转之间进行的操作,也可以认为是在原图上做的操作。主要方式包括AutoAugmentRandAugment,基于一定的策略,包括锐化、亮度变化、直方图均衡化等,对图像进行处理。这样网络在训练时就已经见过这些情况了,之后在实际预测时,即使遇到了光照变换、旋转这些很棘手的情况,网络也可以从容应对了。
  2. 图像裁剪类:图像裁剪类主要是在生成的在通道转换之后,在图像上设置掩码,随机遮挡,从而使得网络去学习一些非显著性的特征。否则网络一直学习很重要的显著性区域,之后在预测有遮挡的图片时,泛化能力会很差。主要方式包括:CutOutRandErasingHideAndSeekGridMask。这里需要注意的是,在通道转换前后去做图像裁剪,其实是没有区别的。因为通道转换这个操作不会修改图像的像素值。
  3. 图像混叠类:组完batch之后,图像与图像、标签与标签之间进行混合,形成新的batch数据,然后送进网络进行训练。这也就是图像混叠类数据增广方式,主要的有MixupCutmix两种方式。

知识点 迁移学习

什么是迁移学习?为什么要用迁移学习

  迁移学习,对于人类来说,就是掌握举一反三的学习能力。比如我们学会骑自行车后,学骑摩托车就很简单了;在学会打羽毛球之后,再学打网球也就没那么难了。对于计算机而言,所谓迁移学习,就是能让现有的模型算法稍加调整即可应用于一个新的领域和功能的一项技术。

  迁移学习(Transfer learning) 顾名思义就是就是把已学训练好的模型参数迁移到新的模型来帮助新模型训练。考虑到大部分数据或任务是存在相关性的,所以通过迁移学习我们可以将已经学到的模型参数(也可理解为模型学到的知识)通过某种方式来分享给新模型从而加快并优化模型的学习效率不用像大多数网络那样从零学习(starting from scratch,tabula rasa)。

  那么我们为什么需要使用迁移学习呢?当你想将一个神经网络应用到一个没有充足数据的新领域当中,同时又有一个巨大的预先训练的数据池可以迁移到你的新任务中的时候,迁移学习将是很有用的。
比如,你可能只有1000张马的图片,但是通过改写一个现成的CNN(例如ResNet,该神经网络已经接受了超过100万张图片的训练),你就能够获得许多底层级和中层级的特征定义。

在自己的数据集上训练分类模型时,更推荐加载预训练进行微调。

预训练模型使用以下方式进行下载。

python tools/download.py -a ResNet50_vd -p ./pretrained -d True

更多的预训练模型可以参考这里:https://paddleclas.readthedocs.io/zh_CN/latest/models/models_intro.html

一、数据增广

在图像分类任务中,图像数据的增广是一种常用的正则化方法,常用于数据量不足或者模型参数较多的场景。在本章节中,我们将对除 ImageNet 分类任务标准数据增广外的8种数据增广方式进行简单的介绍和对比,用户也可以将这些增广方法应用到自己的任务中,以获得模型精度的提升。这8种数据增广方式在ImageNet上的精度指标如下所示。

二、常用数据增广方法

如果没有特殊说明,本章节中所有示例为 ImageNet 分类,并且假设最终输入网络的数据维度为:[batch-size, 3, 224, 224]

其中 ImageNet 分类训练阶段的标准数据增广方式分为以下几个步骤:

  1. 图像解码:简写为 ImageDecode
  2. 随机裁剪到长宽均为 224 的图像:简写为 RandCrop
  3. 水平方向随机翻转:简写为 RandFlip
  4. 图像数据的归一化:简写为 Normalize
  5. 图像数据的重排,[224, 224, 3] 变为 [3, 224, 224]:简写为 Transpose
  6. 多幅图像数据组成 batch 数据,如 batch-size[3, 224, 224] 的图像数据拼组成 [batch-size, 3, 224, 224]:简写为 Batch

相比于上述标准的图像增广方法,研究者也提出了很多改进的图像增广策略,这些策略均是在标准增广方法的不同阶段插入一定的操作,基于这些策略操作所处的不同阶段,我们将其分为了三类:

  1. RandCrop 后的 224 的图像进行一些变换: AutoAugment,RandAugment
  2. Transpose 后的 224 的图像进行一些裁剪: CutOut,RandErasing,HideAndSeek,GridMask
  3. Batch 后的数据进行混合: Mixup,Cutmix

增广后的可视化效果如下所示。

具体如下表所示:

变换方法 输入 输出 Auto-
Augment[1]
Rand-
Augment[2]
CutOut[3] Rand
Erasing[4]
HideAnd-
Seek[5]
GridMask[6] Mixup[7] Cutmix[8]
Image
Decode
Binary (224, 224, 3)
uint8
Y Y Y Y Y Y Y Y
RandCrop (:, :, 3)
uint8
(224, 224, 3)
uint8
Y Y Y Y Y Y Y Y
Process (224, 224, 3)
uint8
(224, 224, 3)
uint8
Y Y - - - - - -
RandFlip (224, 224, 3)
uint8
(224, 224, 3)
float32
Y Y Y Y Y Y Y Y
Normalize (224, 224, 3)
uint8
(3, 224, 224)
float32
Y Y Y Y Y Y Y Y
Transpose (224, 224, 3)
float32
(3, 224, 224)
float32
Y Y Y Y Y Y Y Y
Process (3, 224, 224)
float32
(3, 224, 224)
float32
- - Y Y Y Y - -
Batch (3, 224, 224)
float32
(N, 3, 224, 224)
float32
Y Y Y Y Y Y Y Y
Process (N, 3, 224, 224)
float32
(N, 3, 224, 224)
float32
- - - - - - Y Y

PaddleClas中集成了上述所有的数据增广策略,每种数据增广策略的参考论文与参考开源代码均在下面的介绍中列出。下文将介绍这些策略的原理与使用方法,并以下图为例,对变换后的效果进行可视化。为了说明问题,本章节中将 RandCrop 替换为 Resize

三、图像变换类

图像变换类指的是对 RandCrop 后的 224 的图像进行一些变换,主要包括

  • AutoAugment
  • RandAugment

3.1 AutoAugment

论文地址:https://arxiv.org/abs/1805.09501v1

开源代码github地址:https://github.com/DeepVoltaire/AutoAugment

不同于常规的人工设计图像增广方式,AutoAugment 是在一系列图像增广子策略的搜索空间中通过搜索算法找到的适合特定数据集的图像增广方案。针对 ImageNet 数据集,最终搜索出来的数据增广方案包含 25 个子策略组合,每个子策略中都包含两种变换,针对每幅图像都随机的挑选一个子策略组合,然后以一定的概率来决定是否执行子策略中的每种变换。

PaddleClas中AutoAugment的使用方法如下所示。

from ppcls.data.imaug import DecodeImage
from ppcls.data.imaug import ResizeImage
from ppcls.data.imaug import AutoAugment
from ppcls.data.imaug import transformsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
autoaugment_op = ImageNetPolicy()ops = [decode_op, resize_op, autoaugment_op]imgs_dir = 图像路径
fnames = os.listdir(imgs_dir)
for f in fnames:data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)

结果如下图所示。

3.2 RandAugment

论文地址:https://arxiv.org/pdf/1909.13719.pdf

开源代码github地址:https://github.com/heartInsert/randaugment

AutoAugment 的搜索方法比较暴力,直接在数据集上搜索针对该数据集的最优策略,其计算量很大。在 RandAugment 文章中作者发现,一方面,针对越大的模型,越大的数据集,使用 AutoAugment 方式搜索到的增广方式产生的收益也就越小;另一方面,这种搜索出的最优策略是针对该数据集的,其迁移能力较差,并不太适合迁移到其他数据集上。

RandAugment 中,作者提出了一种随机增广的方式,不再像 AutoAugment 中那样使用特定的概率确定是否使用某种子策略,而是所有的子策略都会以同样的概率被选择到,论文中的实验也表明这种数据增广方式即使在大模型的训练中也具有很好的效果。

PaddleClas中RandAugment的使用方法如下所示。

from ppcls.data.imaug import DecodeImage
from ppcls.data.imaug import ResizeImage
from ppcls.data.imaug import RandAugment
from ppcls.data.imaug import transformsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
randaugment_op = RandAugment()ops = [decode_op, resize_op, randaugment_op]imgs_dir = 图像路径
fnames = os.listdir(imgs_dir)
for f in fnames:data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)

结果如下图所示。

四、图像裁剪类

图像裁剪类主要是对Transpose 后的 224 的图像进行一些裁剪,并将裁剪区域的像素值置为特定的常数(默认为0),主要包括:

  • CutOut
  • RandErasing
  • HideAndSeek
  • GridMask

图像裁剪的这些增广并非一定要放在归一化之后,也有不少实现是放在归一化之前的,也就是直接对 uint8 的图像进行操作,两种方式的差别是:如果直接对 uint8 的图像进行操作,那么再经过归一化之后被裁剪的区域将不再是纯黑或纯白(减均值除方差之后像素值不为0)。而对归一后之后的数据进行操作,裁剪的区域会是纯黑或纯白。

上述的裁剪变换思路是相同的,都是为了解决训练出的模型在有遮挡数据上泛化能力较差的问题,不同的是他们的裁剪方式、区域不太一样。

4.1 Cutout

论文地址:https://arxiv.org/abs/1708.04552

开源代码github地址:https://github.com/uoguelph-mlrg/Cutout

Cutout 可以理解为 Dropout 的一种扩展操作,不同的是 Dropout 是对图像经过网络后生成的特征进行遮挡,而 Cutout 是直接对输入的图像进行遮挡,相对于Dropout对噪声的鲁棒性更好。作者在论文中也进行了说明,这样做法有以下两点优势:(1) 通过 Cutout 可以模拟真实场景中主体被部分遮挡时的分类场景;(2) 可以促进模型充分利用图像中更多的内容来进行分类,防止网络只关注显著性的图像区域,从而发生过拟合。

PaddleClas中Cutout的使用方法如下所示。

from ppcls.data.imaug import DecodeImage
from ppcls.data.imaug import ResizeImage
from ppcls.data.imaug import Cutout
from ppcls.data.imaug import transformsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
cutout_op = Cutout(n_holes=1, length=112)ops = [decode_op, resize_op, cutout_op]imgs_dir = 图像路径
fnames = os.listdir(imgs_dir)
for f in fnames:data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)

结果如下图所示。

4.2 RandomErasing

论文地址:https://arxiv.org/pdf/1708.04896.pdf

开源代码github地址:https://github.com/zhunzhong07/Random-Erasing

RandomErasingCutout 方法类似,同样是为了解决训练出的模型在有遮挡数据上泛化能力较差的问题,作者在论文中也指出,随机裁剪的方式与随机水平翻转具有一定的互补性。作者也在行人再识别(REID)上验证了该方法的有效性。与Cutout不同的是,在RandomErasing中,图片以一定的概率接受该种预处理方法,生成掩码的尺寸大小与长宽比也是根据预设的超参数随机生成。

PaddleClas中RandomErasing的使用方法如下所示。

from ppcls.data.imaug import DecodeImage
from ppcls.data.imaug import ResizeImage
from ppcls.data.imaug import ToCHWImage
from ppcls.data.imaug import RandomErasing
from ppcls.data.imaug import transformsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
randomerasing_op = RandomErasing()ops = [decode_op, resize_op, tochw_op, randomerasing_op]imgs_dir = 图像路径
fnames = os.listdir(imgs_dir)
for f in fnames:data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)img = img.transpose((1, 2, 0))

结果如下图所示。

4.3 HideAndSeek

论文地址:https://arxiv.org/pdf/1811.02545.pdf

开源代码github地址:https://github.com/kkanshul/Hide-and-Seek

HideAndSeek论文将图像分为若干块区域(patch),对于每块区域,都以一定的概率生成掩码,不同区域的掩码含义如下图所示。

PaddleClas中HideAndSeek的使用方法如下所示。

from ppcls.data.imaug import DecodeImage
from ppcls.data.imaug import ResizeImage
from ppcls.data.imaug import ToCHWImage
from ppcls.data.imaug import HideAndSeek
from ppcls.data.imaug import transformsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
hide_and_seek_op = HideAndSeek()ops = [decode_op, resize_op, tochw_op, hide_and_seek_op]imgs_dir = 图像路径
fnames = os.listdir(imgs_dir)
for f in fnames:data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)img = img.transpose((1, 2, 0))

结果如下图所示。

4.4 GridMask

论文地址:https://arxiv.org/abs/2001.04086

开源代码github地址:https://github.com/akuxcw/GridMask

作者在论文中指出,此前存在的基于对图像 crop 的方法存在两个问题,如下图所示:

  1. 过度删除区域可能造成目标主体大部分甚至全部被删除,或者导致上下文信息的丢失,导致增广后的数据成为噪声数据;
  2. 保留过多的区域,对目标主体及上下文基本产生不了什么影响,失去增广的意义。

因此如果避免过度删除或过度保留成为需要解决的核心问题。

GridMask是通过生成一个与原图分辨率相同的掩码,并将掩码进行随机翻转,与原图相乘,从而得到增广后的图像,通过超参数控制生成的掩码网格的大小。

在训练过程中,有两种以下使用方法:

  1. 设置一个概率p,从训练开始就对图片以概率p使用GridMask进行增广。
  2. 一开始设置增广概率为0,随着迭代轮数增加,对训练图片进行GridMask增广的概率逐渐增大,最后变为p。

论文中验证上述第二种方法的训练效果更好一些。

PaddleClas中GridMask的使用方法如下所示。

from data.imaug import DecodeImage
from data.imaug import ResizeImage
from data.imaug import ToCHWImage
from data.imaug import GridMask
from data.imaug import transformsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
tochw_op = ToCHWImage()
gridmask_op = GridMask(d1=96, d2=224, rotate=1, ratio=0.6, mode=1, prob=0.8)ops = [decode_op, resize_op, tochw_op, gridmask_op]imgs_dir = 图像路径
fnames = os.listdir(imgs_dir)
for f in fnames:data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)img = img.transpose((1, 2, 0))

结果如下图所示。

五、图像混叠

图像混叠主要对 Batch 后的数据进行混合,包括:

  • Mixup
  • Cutmix

前文所述的图像变换与图像裁剪都是针对单幅图像进行的操作,而图像混叠是对两幅图像进行融合,生成一幅图像,两种方法的主要区别为混叠的方式不太一样。

5.1 Mixup

论文地址:https://arxiv.org/pdf/1710.09412.pdf

开源代码github地址:https://github.com/facebookresearch/mixup-cifar10

Mixup 是最先提出的图像混叠增广方案,其原理简单、方便实现,不仅在图像分类上,在目标检测上也取得了不错的效果。为了便于实现,通常只对一个 batch 内的数据进行混叠,在 Cutmix 中也是如此。

如下是 imaug 中的实现,需要指出的是,下述实现会出现对同一幅进行相加的情况,也就是最终得到的图和原图一样,随着 batch-size 的增加这种情况出现的概率也会逐渐减小。

PaddleClas中Mixup的使用方法如下所示。

from ppcls.data.imaug import DecodeImage
from ppcls.data.imaug import ResizeImage
from ppcls.data.imaug import ToCHWImage
from ppcls.data.imaug import transform
from ppcls.data.imaug import MixupOperatorsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
tochw_op = ToCHWImage()
hide_and_seek_op = HideAndSeek()
mixup_op = MixupOperator()
cutmix_op = CutmixOperator()ops = [decode_op, resize_op, tochw_op]imgs_dir = 图像路径batch = []
fnames = os.listdir(imgs_dir)
for idx, f in enumerate(fnames):data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)batch.append( (img, idx) ) # fake labelnew_batch = mixup_op(batch)

结果如下图所示。

5.2 Cutmix

论文地址:https://arxiv.org/pdf/1905.04899v2.pdf

开源代码github地址:https://github.com/clovaai/CutMix-PyTorch

Mixup 直接对两幅图进行相加不一样,Cutmix 是从一幅图中随机裁剪出一个 ROI,然后覆盖当前图像中对应的区域,代码实现如下所示:

rom ppcls.data.imaug import DecodeImage
from ppcls.data.imaug import ResizeImage
from ppcls.data.imaug import ToCHWImage
from ppcls.data.imaug import transform
from ppcls.data.imaug import CutmixOperatorsize = 224decode_op = DecodeImage()
resize_op = ResizeImage(size=(size, size))
tochw_op = ToCHWImage()
hide_and_seek_op = HideAndSeek()
cutmix_op = CutmixOperator()ops = [decode_op, resize_op, tochw_op]imgs_dir = 图像路径batch = []
fnames = os.listdir(imgs_dir)
for idx, f in enumerate(fnames):data = open(os.path.join(imgs_dir, f)).read()img = transform(data, ops)batch.append( (img, idx) ) # fake labelnew_batch = cutmix_op(batch)

结果如下图所示。

六、实验

基于PaddleClas,在ImageNet1k数据集上的分类精度如下。

模型 初始学习率策略 l2 decay batch size epoch 数据变化策略 Top1 Acc 论文中结论
ResNet50 0.1/cosine_decay 0.0001 256 300 标准变换 0.7731 -
ResNet50 0.1/cosine_decay 0.0001 256 300 AutoAugment 0.7795 0.7763
ResNet50 0.1/cosine_decay 0.0001 256 300 mixup 0.7828 0.7790
ResNet50 0.1/cosine_decay 0.0001 256 300 cutmix 0.7839 0.7860
ResNet50 0.1/cosine_decay 0.0001 256 300 cutout 0.7801 -
ResNet50 0.1/cosine_decay 0.0001 256 300 gridmask 0.7785 0.7790
ResNet50 0.1/cosine_decay 0.0001 256 300 random-augment 0.7770 0.7760
ResNet50 0.1/cosine_decay 0.0001 256 300 random erasing 0.7791 -
ResNet50 0.1/cosine_decay 0.0001 256 300 hide and seek 0.7743 0.7720

注意

  • 在这里的实验中,为了便于对比,我们将l2 decay固定设置为1e-4,在实际使用中,我们推荐尝试使用更小的l2 decay。结合数据增广,我们发现将l2 decay由1e-4减小为7e-5均能带来至少0.3~0.5%的精度提升。
  • 我们目前尚未对不同策略进行组合并验证效果,这一块后续我们会开展更多的对比实验,敬请期待。

七、数据增广分类实战

本节将基于ImageNet-1K的数据集详细介绍数据增广实验。

7.1 参数配置

由于不同的数据增广方式含有不同的超参数,为了便于理解和使用,我们在configs/DataAugment里分别列举了8种训练ResNet50的数据增广方式的参数配置文件,用户可以在tools/run.sh里直接替换配置文件的路径即可使用。此处分别挑选了图像变换、图像裁剪、图像混叠中的一个示例展示,其他参数配置用户可以自查配置文件。

RandAugment

RandAugment的图像增广方式的配置如下,其中用户需要指定其中的参数num_layersmagnitude,默认的数值分别是25RandAugment是在uint8的数据格式上转换的,所以其处理过程应该放在归一化操作(NormalizeImage)之前。

    transforms:- DecodeImage:to_rgb: Trueto_np: Falsechannel_first: False- RandCropImage:size: 224- RandFlipImage:flip_code: 1- RandAugment:num_layers: 2magnitude: 5- NormalizeImage:scale: 1./255.mean: [0.485, 0.456, 0.406]std: [0.229, 0.224, 0.225]order: ''- ToCHWImage:

Cutout

Cutout的图像增广方式的配置如下,其中用户需要指定其中的参数n_holeslength,默认的数值分别是1112。类似其他图像裁剪类的数据增广方式,Cutout既可以在uint8格式的数据上操作,也可以在归一化(NormalizeImage)后的数据上操作,此处给出的是在归一化后的操作。

    transforms:- DecodeImage:to_rgb: Trueto_np: Falsechannel_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: ''- Cutout:n_holes: 1length: 112- ToCHWImage:

Mixup

Mixup的图像增广方式的配置如下,其中用户需要指定其中的参数alpha,默认的数值是0.2。类似其他图像混合类的数据增广方式,Mixup是在图像做完数据处理后将每个batch内的数据做图像混叠,将混叠后的图像和标签输入网络中训练,所以其是在图像数据处理(图像变换、图像裁剪)后操作。另外,在配置文件中,需要将use_mix参数设置为True

    transforms:- DecodeImage:to_rgb: Trueto_np: Falsechannel_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

7.2 启动命令

当用户配置完训练环境后,类似于训练其他分类任务,只需要将tools/run.sh中的配置文件替换成为相应的数据增广方式的配置文件即可。

其中run.sh中的内容如下:

export PYTHONPATH=path_to_PaddleClas:$PYTHONPATHpython -m paddle.distributed.launch \--selected_gpus="0,1,2,3" \--log_dir=ResNet50_Cutout \tools/train.py \-c ./configs/DataAugment/ResNet50_Cutout.yaml

运行run.sh

sh tools/run.sh

7.3 注意事项

  • 在使用图像混叠类的数据处理时,需要将配置文件中的use_mix设置为True,另外由于图像混叠时需对label进行混叠,无法计算训练数据的准确率,所以在训练过程中没有打印训练准确率。

  • 在使用数据增广后,由于训练数据更难,所以训练损失函数可能较大,训练集的准确率相对较低,但其有拥更好的泛化能力,所以验证集的准确率相对较高。

  • 在使用数据增广后,模型可能会趋于欠拟合状态,建议可以适当的调小l2_decay的值来获得更高的验证集准确率。

  • 几乎每一类图像增广均含有超参数,我们只提供了基于ImageNet-1k的超参数,其他数据集需要用户自己调试超参数,具体超参数的含义用户可以阅读相关的论文,调试方法也可以参考训练技巧的章节。

如果您觉得此文档对您有帮助,欢迎star我们的项目:https://github.com/PaddlePaddle/PaddleClas

参考文献

[1] Cubuk E D, Zoph B, Mane D, et al. Autoaugment: Learning augmentation strategies from data[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2019: 113-123.

[2] Cubuk E D, Zoph B, Shlens J, et al. Randaugment: Practical automated data augmentation with a reduced search space[J]. arXiv preprint arXiv:1909.13719, 2019.

[3] DeVries T, Taylor G W. Improved regularization of convolutional neural networks with cutout[J]. arXiv preprint arXiv:1708.04552, 2017.

[4] Zhong Z, Zheng L, Kang G, et al. Random erasing data augmentation[J]. arXiv preprint arXiv:1708.04896, 2017.

[5] Singh K K, Lee Y J. Hide-and-seek: Forcing a network to be meticulous for weakly-supervised object and action localization[C]//2017 IEEE international conference on computer vision (ICCV). IEEE, 2017: 3544-3553.

[6] Chen P. GridMask Data Augmentation[J]. arXiv preprint arXiv:2001.04086, 2020.

[7] Zhang H, Cisse M, Dauphin Y N, et al. mixup: Beyond empirical risk minimization[J]. arXiv preprint arXiv:1710.09412, 2017.

[8] Yun S, Han D, Oh S J, et al. Cutmix: Regularization strategy to train strong classifiers with localizable features[C]//Proceedings of the IEEE International Conference on Computer Vision. 2019: 6023-6032.

3.4 数据增广的尝试-RandomErasing

  • 训练数据量较小时,使用数据增广可以进一步提升模型精度,基于3.3节中的训练方法,结合RandomErasing的数据增广方式进行训练,配置文件中的训练集配置如下所示。
TRAIN:batch_size: 32num_workers: 4file_list: "./dataset/flowers102/train_list.txt"data_dir: "./dataset/flowers102/"shuffle_seed: 0transforms:- DecodeImage:to_rgb: Trueto_np: Falsechannel_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: # 在归一化之后使用RandomErasing方法进行数据增广EPSILON: 0.5- ToCHWImage:

具体的训练脚本如下所示。

export PYTHONPATH=$PWD:$PYTHONPATH
python -m paddle.distributed.launch \--selected_gpus="0" \tools/train.py \-c ./configs/quick_start/ResNet50_vd_ssld_random_erasing_finetune.yaml

可以在命令行中拷贝代码框中的内容运行训练过程,也可以通过sh shell/run_r50_vd_ssld_finetune_random_erasing.sh的命令去运行该训练过程。

训练开始后,可以在终端中实时查看训练集验证集的loss与准确率等信息。

配置文件详解

配置说明


简介

本文档介绍了PaddleClas配置文件(configs/*.yaml)中各参数的含义,以便您更快地自定义或修改超参数配置。

  • 注意:部分参数并未在配置文件中体现,在训练或者评估时,可以直接使用-o进行参数的扩充或者更新,比如说-o checkpoints=./ckp_path/ppcls,表示在配置文件中添加(如果之前不存在)或者更新(如果之前已经包含该字段)checkpoints字段,其值设为./ckp_path/ppcls

配置详解

基础配置

参数名字 具体含义 默认值 可选值
mode 运行模式 “train” [“train”," valid"]
checkpoints 断点模型路径,用于恢复训练 “” Str
last_epoch 上一次训练结束时已经训练的epoch数量,与checkpoints一起使用 -1 int
pretrained_model 预训练模型路径 “” Str
load_static_weights 加载的模型是否为静态图的预训练模型 False bool
model_save_dir 保存模型路径 “” Str
classes_num 分类数 1000 int
total_images 总图片数 1281167 int
save_interval 每隔多少个epoch保存模型 1 int
validate 是否在训练时进行评估 TRUE bool
valid_interval 每隔多少个epoch进行模型评估 1 int
epochs 训练总epoch数 int
topk 评估指标K值大小 5 int
image_shape 图片大小 [3,224,224] list, shape: (3,)
use_mix 是否启用mixup False [‘True’, ‘False’]
ls_epsilon label_smoothing epsilon值 0 float
use_distillation 是否进行模型蒸馏 False bool

结构(ARCHITECTURE)

参数名字 具体含义 默认值 可选值
name 模型结构名字 “ResNet50_vd” PaddleClas提供的模型结构
params 模型传参 {} 模型结构所需的额外字典,如EfficientNet等配置文件中需要传入padding_type等参数,可以通过这种方式传入

学习率(LEARNING_RATE)

参数名字 具体含义 默认值 可选值
function decay方法名 “Linear” [“Linear”, “Cosine”,
“Piecewise”, “CosineWarmup”]
params.lr 初始学习率 0.1 float
params.decay_epochs piecewisedecay中
衰减学习率的milestone
list
params.gamma piecewisedecay中gamma值 0.1 float
params.warmup_epoch warmup轮数 5 int
parmas.steps lineardecay衰减steps数 100 int
params.end_lr lineardecayend_lr值 0 float

优化器(OPTIMIZER)

参数名字 具体含义 默认值 可选值
function 优化器方法名 “Momentum” [“Momentum”, “RmsProp”]
params.momentum momentum值 0.9 float
regularizer.function 正则化方法名 “L2” [“L1”, “L2”]
regularizer.factor 正则化系数 0.0001 float

数据读取器与数据处理

参数名字 具体含义
batch_size 批大小
num_workers 数据读取器worker数量
file_list train文件列表
data_dir train文件路径
shuffle_seed 用来进行shuffle的seed值

数据处理

功能名字 参数名字 具体含义
DecodeImage to_rgb 数据转RGB
to_np 数据转numpy
channel_first 按CHW排列的图片数据
RandCropImage size 随机裁剪
RandFlipImage 随机翻转
NormalizeImage scale 归一化scale值
mean 归一化均值
std 归一化方差
order 归一化顺序
ToCHWImage 调整为CHW
CropImage size 裁剪大小
ResizeImage resize_short 按短边调整大小

mix处理

参数名字 具体含义
MixupOperator.alpha mixup处理中的alpha值

知识点 CosineWarmup

总结

  • 本教程希望能够让大家对PaddleClas有一个直观的认识,并带领大家进行图像分类竞赛实战。更多丰富的内容与示例可以参考PaddleClas的github与教程文档。

    • PaddleClas github地址:https://github.com/PaddlePaddle/PaddleClas/
    • PaddleClas教程文档地址:https://paddleclas.readthedocs.io/zh_CN/latest/index.html
  • 如果大家在使用PaddleClas的过程中遇到问题,欢迎去PaddleClas的github上提issue:https://github.com/PaddlePaddle/PaddleClas/issues/new

基于飞桨图像分类套件PaddleClas的柠檬分类竞赛实战相关推荐

  1. 基于飞桨与OpenVINO 的智能机器人开发实践 | 开发者实战

    谈到机器人,我们首先要知道什么是机器人 这是从百度百科截取的我国科学家对于机器人的定义 机器人是一种自动化的机器,这种机器人具备一些人或生物相似的智能能力,如感知能力.规划能力.动作能力.协同能力.是 ...

  2. 【AI Studio】飞桨图像分类零基础训练营 - 0456 - 图像分类竞赛全流程实战

    前言:因为两课讲的一个比赛内容(课程里也没分页),所以我把笔记也合在一起.而且也是因为老师讲得很飘,所以我感觉我想记的东西估计不多吧.因为大部分都是新概念,所以我自己也没什么全新的理解,基本都是复制粘 ...

  3. [C4AI_2022]基于飞桨的无人机智能工地安全监管系统

    ★★★ 本文源自AI Studio社区精品项目,[点击此处]查看更多精品内容 >>> 基于飞桨的无人机智能工地安全监管系统 项目展示 scrolling="no" ...

  4. 基于飞桨复现图像分类模型TNT,实现肺炎CT分类

    本项目介绍了TNT图像分类模型,讲述了如何使用飞桨一步步构建TNT模型网络结构,并尝试在新冠肺炎CT数据集上进行分类.由于作者水平有限,若有不当之处欢迎批评指正. TNT模型介绍 TNT模型全称是Tr ...

  5. 【AI Studio】飞桨图像分类零基础训练营 - 01 - 图像处理基本概念

    前言:这里是图像分类的第一课笔记,如题,第一节可主要讲述了图像处理的操作,也就是数据集处理.根据之前学过的知识理解,训练集往往是有限的,为了扩大训练集,总会人为的制造数据.这时数据处理就体现了.而且实 ...

  6. 基于飞桨复现语义分割网络HRNet,实现瓷砖缺陷检测

    点击左上方蓝字关注我们 [飞桨开发者说]路星奎,沈阳化工大学信息工程学院研究生在读,PPDE飞桨开发者技术专家,研究方向为图像分类.目标检测.图像分割等 内容简介 本项目讲述了HRNet网络结构,并尝 ...

  7. 【AI Studio】飞桨图像分类零基础训练营 - 03 - 卷积神经网络基础

    前言:第三天,老师结合ppt文图详细讲解了线性和卷积网络的构建,由简单到复杂的讲解卷积网络的发展.最后结合几个项目加深理解.愈发感觉老师讲的好了.第二天的课听完后还感觉自己什么都懂了,结果轮到自己动手 ...

  8. 赛桨PaddleScience v1.0 Beta:基于飞桨核心框架的科学计算通用求解器

    近年来,关于AI for Science的主题被广泛讨论,重点领域包含使用AI方法加速设计并发现新材料,助力高能物理及天文领域的新问题探索,以及加速智慧工业实时设备数据与模型的"数字孪生&q ...

  9. 基于飞桨的小样本学习工具包助你举一反三

    王雅晴,PaddleFSL负责人.飞桨高级开发者技术专家(高级PPDE).2019年博士毕业于香港科技大学计算机科学及工程学系.通过百度公司AIDU计划加入百度研究院商业智能实验室,现任资深研发工程师 ...

最新文章

  1. 嵌入式系统功能需求分析_超市监控系统的功能作用分析
  2. 在vim中设置将tab自动转化为4个空格
  3. 修改httpd默认端口号
  4. Java中怎么样检查一个字符串是不是数字呢
  5. oracle分页查询过程的简单实现
  6. Mozilla推动互联网成为游戏发展的强有力平台
  7. Web前端性能优化——CSS优化
  8. 智能小车寻迹c语言程序,智能小车循迹记时测速程序
  9. 华为网络,模拟器ensp的基本使用
  10. 看英语数据手册很难?5步帮你搞定!
  11. CSS基础:浅用字体图标(以阿里字体图标库演示)
  12. HNUCM 1366 绿地装饰解题报告 (模拟)
  13. 微信公众号服务器搭建
  14. DVFS--动态电压频率调整
  15. LK光流算法的matlab仿真与仿真
  16. xuexi.cn-app处理记录
  17. 埃哲森:物联网市场潜力达万亿美元
  18. Windows11打不开Windows安全中心解决方法
  19. 我的 Python.color() (Python 色彩打印控制)
  20. Master PDF Editor v5.7.91 最小巧的PDF编辑器便携版

热门文章

  1. 【C语言游戏】太空大战 | SpaceWar(基于EasyX图形库,FPS优化,碰撞判断,drawAlpha绘制透明贴图,音乐播放,源码素材免费分享)
  2. 【教学类-16-01】20221121《数字卡片9*2》(中班)
  3. QGtkStyle was unable to detect the current GTK+ theme
  4. Python安装第三方库的常用方法:使用pip
  5. 三轮车出口欧盟没做e-mark认证会怎样?
  6. 计算机技术非全日制调剂2020,2020年硕士研究生部分非全日制专业接收调剂的公告...
  7. 【新手教程】51Sim-One Cloud 2.0如何构建一个V2X案例
  8. UPC第41场,第42场部分题解
  9. 【BP回归预测】基于matlab随机蛙跳算法SFLA优化神经网络数据回归预测【含Matlab源码 2272期】
  10. Python Re正则表达式