paddlex训练模型以目标检测为例

paddlex版本问题

前一天paddlex2.0还可以用,第二天就报版本的问题,解决方法就是重装1.3的版本

PaddleX/tutorials/train at release/2.0-rc · PaddlePaddle/PaddleX (github.com)

本教程使用到的数据集

VOC车辆

0. paddlex API

API接口说明 — PaddleX 文档

目标检测PascalVOC — PaddleX 文档

1. 相关库下载

在本地如果还没有安装飞桨的,还要提前安装pip paddlepaddle

!pip install paddlex -i https://mirror.baidu.com/pypi/simple
!pip install imgaug -i https://mirror.baidu.com/pypi/simple
!pip install paddlehub==1.6.2
!pip show paddlex

2. 数据处理

1.划分训练集验证集

为了用于训练,我们需要在MyDataset目录下准备train_list.txt, val_list.txtlabels.txt三个文件,分别用于表示训练集列表,验证集列表和类别标签列表。点击下载目标检测示例数据集

注:也可使用PaddleX自带工具,对数据集进行随机划分,在数据集按照上面格式组织后,使用如下命令即可快速完成数据集随机划分,其中val_value表示验证集的比例,test_value表示测试集的比例(可以为0),剩余的比例用于训练集。

paddlex --split_dataset --format VOC --dataset_dir MyDataset --val_value 0.2 --test_value 0.1
# 数据划分,生成txt文件
import cv2
import os
from tqdm import tqdm
from random import shuffle
# 划分的标签
labels = ['car', 'van', 'bus', 'others']

# 文件的公共路径
base ='VOCData/'
# 图片文件名列表
imgs=[v for v in os.listdir(base+'JPEGImages')]
# 划分数据集,这里划分  训练:测试=7:3
len_imgs=len(imgs)
len_train=int(0.7*len_imgs)

print("训练集长度为 {}".format(len_train))
print("测试集长度为 {}".format(len_eval))
train_imgs=imgs[:len_train]
eval_imgs=imgs[len_train:]
# 打乱文件顺序
shuffle(imgs)
# 生成需要的.txt文件
with open('train.txt','w') as f:
    for img in tqdm(train_imgs):
        # 标记文件和图片文件名仅后缀不同
        xml="Annotations/"+img[:-4]+'.xml'
        # 两个合并在一行,中间空格隔开,图片名在前
        info="JPEGImages/"+img+" "+xml
        if not cv2.imread(os.path.join(base+'JPEGImages',img)) is None:
            f.write(info+'\n')
        else:
            print("文件"+img+"不存在")
# 生成测试文件
with open('eval.txt','w') as f:
    for img in tqdm(eval_imgs):
        xml="Annotations/"+img[:-4]+'.xml'
        info="JPEGImages/"+img+" "+xml
        if not cv2.imread(os.path.join(base+'JPEGImages',img)) is None:
            f.write(info+'\n')
        else:
            print("文件"+img+"不存在")
with open('label.txt','w') as f:
    for label in tqdm(labels):
        f.write(label+'\n')

2.数据集文件夹结构

在PaddleX中,目标检测支持PascalVOC数据集格式。建议用户将数据集按照如下方式进行组织,原图均放在同一目录,如JPEGImages,标注的同名xml文件均放在同一目录,如Annotations,示例如下

MyDataset/ # 目标检测数据集根目录
|--JPEGImages/ # 原图文件所在目录
|  |--1.jpg
|  |--2.jpg
|  |--...
|  |--...
|
|--Annotations/ # 标注文件所在目录
|  |--1.xml
|  |--2.xml
|  |--...
|  |--...

labels.txt

labels.txt用于列出所有类别,类别对应行号表示模型训练过程中类别的id(行号从0开始计数),例如labels.txt为以下内容

dog
cat
snake

表示该检测数据集中共有3个目标类别,分别为dogcatsnake,在模型训练中dog对应的类别id为0, cat对应1,以此类推

train_list.txt

train_list.txt列出用于训练时的图片集合,与其对应的标注文件,示例如下

JPEGImages/1.jpg Annotations/1.xml
JPEGImages/2.jpg Annotations/2.xml
... ...

其中第一列为原图相对MyDataset的相对路径,第二列为标注文件相对MyDataset的相对路径

val_list.txt

val_list列出用于验证时的图片集成,与其对应的标注文件,格式与val_list.txt一致

3.数据增强

imgaug 使用简介_Man-CSDN博客

数据增强与imgaug支持 — PaddleX 文档

paddlex.det.transforms — PaddleX 文档

# 数据增强
from paddlex.det import transforms
import imgaug.augmenters as iaa
trian_transforms=transforms.Compose([
    #随机裁剪
    transforms.RandomCrop(),
    #消除噪点
    iaa.GaussianBlur(sigma=(0.0,3.0)),
    iaa.MultiplyAndAddToBrightness(mul=(0.5, 1.5), add=(-30, 30)),
    iaa.Cutout(fill_mode="constant", cval=(0, 255), fill_per_channel=0.5),
    # 随机水平翻转
    transforms.RandomHorizontalFlip(),
    iaa.SaltAndPepper(0.1),
    # 裁剪 插值方法:随机
    # transforms.Resize(target_size=608, interp='RANDOM'),
    # 图像归一化
    transforms.Normalize(),
])
eval_transforms = transforms.Compose([
    # transforms.Resize(target_size=608, interp='CUBIC'),
    # 图像归一化
    transforms.Normalize(),
])

4.数据集加载

# 数据加载
import paddlex
base ='VOCData/'
train_dataset=paddlex.datasets.VOCDetection(
    data_dir=base,
    # data_dir=base,
    file_list='train.txt',
    label_list='label.txt',
    transforms=trian_transforms,
    shuffle=True
)
eval_dataset=paddlex.datasets.VOCDetection(
    data_dir=base,
    file_list='eval.txt',
    label_list='label.txt',
    transforms=eval_transforms,
)

3. 训练模型

视觉模型集 — PaddleX 文档

训练参数调整 — PaddleX 文档

# 训练模型
num_class=len(train_dataset.labels)
print("检测类别数:{}".format(num_class))
# 选择模型
model=paddlex.det.YOLOv3(num_classes=num_class,backbone='MobileNetV3_large')
model.train(
    num_epochs=50,
    train_dataset=train_dataset,
    # 至尊 32G内存,利用率在80%train_batch_size=32时,
    train_batch_size=8,
    eval_dataset=eval_dataset,
    learning_rate=0.0000125,
    warmup_steps=100,
    lr_decay_epochs=[30, 38],
    save_interval_epochs=32,
    log_interval_steps=100,
    save_dir='./VehicleDetection',
    pretrain_weights='VehicleDetection/best_model',
    use_vdl=True,
    resume_checkpoint='VehicleDetection/best_model'
    )

训练指标

PaddleX指标及日志 — PaddleX 文档

../_images/seg_train.png

Epoch Epoch=4/20 [迭代轮数]所有训练数据会被训练20轮,当前处于第4轮
Step Step=62/66 [迭代步数]所有训练数据被训练一轮所需要的迭代步数为66,当前处于第62步
loss loss=0.007226 [损失函数值]参与当前迭代步数的训练样本的平均损失函数值loss,loss值越低,表明模型在训练集上拟合的效果越好(如上日志中第1行表示第4个epoch的第62个Batch的loss值为0.007226)
lr lr=0.008215 [学习率]当前模型迭代过程中的学习率
time_each_step time_each_step=0.41s [每步迭代时间]训练过程计算得到的每步迭代平均用时
eta eta=0:9:44 [剩余时间]模型训练完成所需剩余时间预估为0小时9分钟44秒

评估通用统计信息

PaddleX所有模型在训练过程中会根据用户设定的save_interval_epochs参数,每间隔一定轮数进行评估和保存。例如分类模型的评估日志,如下图所示。

../_images/cls_eval.png

上图中第1行表明验证数据集中样本数为240,需要迭代8步才能评估完所有验证数据;第5行用于表明第2轮的模型已经完成保存操作;第6行则表明当前保存的模型中,第2轮的模型在验证集上指标最优(分类任务看acc1,此时acc1值为0.258333),最优模型会保存在best_model目录中。

训练参数调整

PaddleX所有训练接口中,内置的参数均为根据单GPU卡相应batch_size下的较优参数,用户在自己的数据上训练模型,涉及到参数调整时,如无太多参数调优经验,则可参考如下方式

0.如何使用多GPU卡进行训练

import paddlex前配置环境变量,代码如下

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0' # 使用0号GPU卡进行训练
# 注意paddle或paddlex都需要在设置环境变量后再import
import paddlex as pdx
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '' # 不使用GPU,使用CPU进行训练
import paddlex as pdx
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1,3' # 同时使用第0、1、3号GPU卡进行训练
import paddlex as pdx

1.num_epochs的调整

num_epochs是模型训练迭代的总轮数(模型对训练集全部样本过一遍即为一个epoch),用户可以设置较大的数值,根据模型迭代过程在验证集上的指标表现,来判断模型是否收敛,进而提前终止训练。此外也可以使用train接口中的early_stop策略,模型在训练过程会自动判断模型是否收敛自动中止。

2.batch_size和learning_rate

  • Batch Size指模型在训练过程中,前向计算一次(即为一个step)所用到的样本数量
  • 如若使用多卡训练, batch_size会均分到各张卡上(因此需要让batch size整除卡数)
  • Batch Size跟机器的显存/内存高度相关,batch_size越高,所消耗的显存/内存就越高
  • PaddleX在各个train接口中均配置了默认的batch size(默认针对单GPU卡),如若训练时提示GPU显存不足,则相应调低BatchSize,如若GPU显存高或使用多张GPU卡时,可相应调高BatchSize。
  • 如若用户调整batch size,则也注意需要对应调整其它参数,特别是train接口中默认的learning_rate值。如在YOLOv3模型中,默认train_batch_size为8,learning_rate为0.000125,当用户将模型在2卡机器上训练时,可以将train_batch_size调整为16, 那么同时learning_rate也可以对应调整为0.000125 * 2 = 0.00025

3.warmup_steps和warmup_start_lr

在训练模型时,一般都会使用预训练模型,例如检测模型在训练时使用backbone在ImageNet数据集上的预训练权重。但由于在自行训练时,自己的数据与ImageNet数据集存在较大的差异,可能会一开始由于梯度过大使得训练出现问题,这种情况下可以在刚开始训练时,让学习率以一个较小的值,慢慢增长到设定的学习率。warmup_stepswarmup_start_lr就是起到这个作用,模型开始训练时,学习率会从warmup_start_lr开始,在warmup_steps个batch数据迭代后线性增长到设定的学习率。

例如YOLOv3的train接口,默认train_batch_size为8,learning_rate为0.000125, warmup_steps为1000, warmup_start_lr为0.0;在此参数配置下表示,模型在启动训练后,在前1000个step(每个step使用一个batch的数据,即8个样本)内,学习率会从0.0开始线性增长到设定的0.000125。

4.lr_decay_epochs和lr_decay_gamma

lr_decay_epochs用于让学习率在模型训练后期逐步衰减,它一般是一个list,如[6, 8, 10],表示学习率在第6个epoch时衰减一次,第8个epoch时再衰减一次,第10个epoch时再衰减一次。每次学习率衰减为之前的学习率*lr_decay_gamma。

例如YOLOv3的train接口,默认num_epochs为270,learning_rate为0.000125, lr_decay_epochs为[213, 240],lr_decay_gamma为0.1;在此参数配置下表示,模型在启动训练后,在前213个epoch中,训练时使用的学习率为0.000125,在第213至240个epoch之间,训练使用的学习率为0.000125x0.1=0.0000125,在240个epoch之后,使用的学习率为0.000125x0.1x0.1=0.00000125

5.参数设定时的约束

根据上述几个参数,可以了解到学习率的变化分为WarmUp热身阶段和Decay衰减阶段,

  • Wamup热身阶段:随着训练迭代,学习率从较低的值逐渐线性增长至设定的值,以step为单位
  • Decay衰减阶段:随着训练迭代,学习率逐步衰减,如每次衰减为之前的0.1, 以epoch为单位
  • step与epoch的关系:1个epoch由多个step组成,例如训练样本有800张图像,train_batch_size为8, 那么每个epoch都要完整用这800张图片训一次模型,而每个epoch总共包含800//8即100个step

在PaddleX中,约束warmup必须在Decay之前结束,因此各参数设置需要满足下面条件

warmup_steps <= lr_decay_epochs[0] * num_steps_each_epoch

其中num_steps_each_epoch计算方式如下,

num_steps_each_eposh = num_samples_in_train_dataset // train_batch_size

因此,如若你在启动训练时,被提示warmup_steps should be less than...时,即表示需要根据上述公式调整你的参数啦,可以调整lr_decay_epochs或者是warmup_steps

4. 模型评估

评估通用统计信息

PaddleX所有模型在训练过程中会根据用户设定的save_interval_epochs参数,每间隔一定轮数进行评估和保存。例如分类模型的评估日志,如下图所示。

../_images/cls_eval.png

上图中第1行表明验证数据集中样本数为240,需要迭代8步才能评估完所有验证数据;第5行用于表明第2轮的模型已经完成保存操作;第6行则表明当前保存的模型中,第2轮的模型在验证集上指标最优(分类任务看acc1,此时acc1值为0.258333),最优模型会保存在best_model目录中。

检测可以使用两种评估标准:VOC评估标准和COCO评估标准。

VOC评估标准

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iv6SAXWq-1630572625178)(C:\Users\86137\AppData\Roaming\Typora\typora-user-images\image-20210831211207590.png)]

注:map为平均准确率的平均值,即IoU(Intersection Over Union)取0.5时各个类别的准确率-召回率曲线下面积的平均值。

上图中第3行bbox_map表示检测任务中整个验证集的平均准确率平均值。

5. 保存模型/导出部署

部署模型导出 — PaddleX 文档

./YOLOv3/best_model 文件下的文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O3KPJLW6-1630572625183)(C:\Users\86137\AppData\Roaming\Typora\typora-user-images\image-20210828002452122.png)]

# --model_dir是模型权重文件 --save_dir是要保存的文件地址
!paddlex --export_inference --model_dir=./YOLOv3/best_model --save_dir=./det_inference_model

6. 模型剪切

模型裁剪 — PaddleX 文档

7. 加载模型

import paddlex as pdx
# 'det_inference_model'是模型权重文件路径
model = pdx.deploy.Predictor('det_inference_model')
image_name = 'demo.jpg'
result = model.predict(image=image_name)
print(len(result))
print(result)
98
[{'category_id': 0, 'bbox': [84.8077392578125, 494.5171203613281, 54.4744873046875, 54.580902099609375], 'score': 0.6862342357635498, 'category': 'pt'}, {'category_id': 0, 'bbox': [301.1315002441406, 498.1654357910156, 48.0050048828125, 45.606719970703125], 'score': 0.6020365953445435, 'category': 'pt'}, {'category_id': 0, 'bbox': [88.00811004638672, 
import paddlex as pdx
test_jpg = 'VOCData/JPEGImages/MVI_20011__img00285.jpg'
model=pdx.deploy.Predictor('det_inference_model')

# predict接口并未过滤低置信度识别结果,用户根据需求按score值进行过滤
result = model.predict(test_jpg)

# 可视化结果存储在'./result', 见下图
pdx.det.visualize(test_jpg, result, threshold=0.2, save_dir='./result')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-URirN7f1-1630572796265)(C:\Users\86137\Downloads\visualize_MVI_20011__img00285.jpg)]

可能存在的问题:

在本地电脑:

# 可视化结果存储在'./result', 见下图
pdx.det.visualize(test_jpg, result, threshold=0.2, save_dir='./result')

出现 Initializing libiomp5md.dll, but found libiomp5md.dll already initialized问题

方式一:(亲测有效)

允许副本存在,忽略报错;在程序开头添加如下代码:

添加语句:

import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

方式二:

把numpy卸载干净再重装。

pip uninstall numpy
pip install numpy

版权声明:本文为CSDN博主「就这这就」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/naexting/article/details/120065054

就这这就

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

yolov5 检测一类物体

使用yolov5官方框架检测一类物体 yolov5的官方框架可较好的对共80种类进行目标检测,本文介绍一种直接修改源代码来只检测一类物体的方法以及通用的方法(利用数据集训练自己的权重)。 一、直接修

yolov5训练数据集划分

yolov5训练数据集划分 按照默认8:1:1划分训练集,测试集,验证集。 txt文件出现在imageset文件夹。 import os import randomtrainval_pe