【基于Paddle框架的行车环境下天气及时间分类】


此项目基于Paddle框架,且是在 BML CodeLab中开发,目的是熟悉Paddle框架的使用,该项目也同时发布在了AI Studio平台。

一、项目简介

在自动驾驶场景中,天气和时间(黎明、早上、下午、黄昏、夜晚)会对传感器的精度造成影响,比如雨天和夜晚会对视觉传感器的精度造成很大的影响。此赛题旨在对拍摄的照片天气和时间进行分类,从而在不同的天气和时间使用不同的自动驾驶策略。

二、数据来源及分析

本项目数据来源于公共数据集:天气及时间分类

数据集中包含3000张真实场景下行车记录仪采集的图片,其中训练集包含2600张带有天气和时间类别标签的图片,测试集包含400张不带有标签的图片。在训练集上进行训练,对测试集中照片的天气和时间进行分类。

天气类别包含多云、晴天、雨天、雪天和雾天5个类别;时间包含黎明、早上、下午、黄昏、夜晚5个类别。

2.1 解压训练数据集

# 解压数据集
!unzip /home/aistudio/data/data145073/train_dataset.zip -d /home/aistudio/work/train

得到文件夹 train_images 和表示训练数据标签的 train.json

三、数据读取

首先我们需要制作ImageNet格式的数据集。

制作ImageNet格式的数据集的原因:

在PaddleX的图像分类任务的官方教程中,在定义和加载数据集阶段,PaddleX读取数据集所采用的为ImageNet格式的分类数据集,因此我们需要先行将官方所提供的数据集转换为符合ImageNet数据集格式要求的数据集,这样才能完成数据集的定义和加载。

参考官方文档 图像分类ImageNet,其中详细介绍了ImageNet数据集的格式,我们需要做的是按照其格式要求,处理上一节解压得到的 train_images 文件夹和 train.json 标签文件

首先介绍下 ImageNet格式的分类数据集:

3.1 ImageNet数据集格式说明

3.1.1 数据文件夹格式

数据集目录 data_dir 下包含多个文件夹,每个文件夹中的图像均属于同一个类别,文件夹的命名即为类别名(注意路径中不要包括中文,空格)。

文件夹结构示例如下:

MyDataset/ # 图像分类数据集根目录
|–dog/ # 当前文件夹所有图片属于dog类别
| |–d1.jpg
| |–d2.jpg
| |–…
| |–…
|
|–…
|
|–snake/ # 当前文件夹所有图片属于snake类别
| |–s1.jpg
| |–s2.jpg
| |–…
| |–…

3.1.2 训练集、验证集列表和类别标签列表

为了完成模型的训练和精度验证。我们需要在MyDataset目录下准备train_list.txt, val_list.txt和labels.txt三个文件,分别用于表示训练集列表,验证集列表和类别标签列表。点击下载图像分类示例数据集查看具体的数据格式。

  1. labels.txt

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

dog
cat
snake

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

  1. train_list.txt

train_list.txt列出用于训练时的图片集合,与其对应的类别id,示例如下

dog/d1.jpg 0
dog/d2.jpg 0
cat/c1.jpg 1
… …
snake/s1.jpg 2

其中第一列为相对对MyDataset的相对路径,第二列为图片对应类别的类别id

  1. val_list.txt

val_list列出用于验证时的图片集成,与其对应的类别id,格式与train_list.txt一致

3.2 获取ImageNet格式的数据集

该项目数据集对比于 3.1 小节中的示例有所不同,其标签包括时间段及天气,这种情况下我们应当如何对其格式进行整理呢?

参考 雾切凉宫——基于ResNet50模型的行车环境下天气时间分类
处理数据集的思路,即把两个标签进行合并,视为一个标签。

import json
import os.path
import shutil

base_dir = "/home/aistudio/work/train"
infos = json.load(open(os.path.join(base_dir, "train.json"), 'r')) 
# r为读模式 r+为读写模式,此处只读不需要写,默认为r,所以也可以不用加
infos = infos['annotations']
# print(infos)
for info in infos:
    filename = info['filename']
    filename = filename[filename.find('\\') + 1:]
    category = info['period'] + '_' + info['weather']
    filename_path = os.path.join(base_dir, 'train_images', filename)
    category_path = os.path.join(base_dir, 'ImageNet_dataset', category, filename)
    try:
        shutil.copy(filename_path, category_path)
    except:
        os.makedirs(os.path.join(base_dir, 'ImageNet_dataset', category))
        shutil.copy(filename_path, category_path)

上述代码所完成的任务为:以图像的类别为文件夹名称,将 train_images 文件夹中的图片不改名称直接复制到对应类别的文件夹中。

接着,我们执行以下命令,使用 paddlex 生成上述获得对应类别文件夹的.txt标签文件

!paddlex --split_dataset --format IMAGENET --dataset_dir /home/aistudio/work/train/ImageNet_dataset --val_value 0.1 --test_value 0.1

至此,我们成功完成了修改已有数据集格式到ImageNet格式

3.3 定义训练/验证图像处理流程transforms及数据集加载

此处参考PaddleX的图像分类任务的官方教程的同名部分以及图像分类ImageNet的数据加载部分,下面对训练集和验证集分别定义其transforms,其中使用了一些数据增强函数,详细可参考数据增强文档

import paddlex as pdx
from paddlex import transforms as T

train_transforms = T.Compose([
     T.RandomCrop(crop_size=224),
     T.RandomHorizontalFlip(),
     T.Normalize()])

eval_transforms = T.Compose([
    T.ResizeByShort(short_size=256),
    T.CenterCrop(crop_size=224),
    T.Normalize()
])

data_dir = r'/home/aistudio/work/train/ImageNet_dataset'

train_dataset = pdx.datasets.ImageNet(
                    data_dir=data_dir,
                    file_list=data_dir + r'/train_list.txt',
                    label_list=data_dir + r'labels.txt',
                    transforms=train_transforms)
eval_dataset = pdx.datasets.ImageNet(
                    data_dir=data_dir,
                    file_list=data_dir + r'val_list.txt',
                    label_list=data_dir + r'labels.txt',
                    transforms=eval_transforms)

其中,pdx.datasets.ImageNet 表示读取ImageNet格式的分类数据集,下面对其参数进行详细说明:

paddlex.datasets.ImageNet(data_dir, file_list, label_list, transforms=None, num_workers='auto', shuffle=False)

data_dir (str): 数据集所在的目录路径。
file_list (str): 描述数据集图片文件和类别id的文件路径(文本内每行路径为相对data_dir的相对路径)。
label_list (str): 描述数据集包含的类别信息文件路径。
transforms (paddlex.transforms): 数据集中每个样本的预处理/增强算子,详见paddlex.transforms。
num_workers (int|str):数据集中样本在预处理过程中的进程数。默认为’auto’。当设为’auto’时,根据系统的实际CPU核数设置num_workers: 如果CPU核数的一半大于8,则num_workers为8,否则为CPU核数的一半。
shuffle (bool): 是否需要对数据集中样本打乱顺序。默认为False。

四、模型训练

4.1 模型选择与调用

paddlex中有很多内置的图像分类模型,详细可参考PaddleX 图像分类模型API,这里我们选择使用PaddleX图像分类模型API的例子模型:MobileNetV3_small

模型可以采用如下代码进行定义:

paddlex.cls.MobileNetV3_small(num_classes=1000)

num_classes (int): 分类类别数。默认为1000。

模型的训练接口如以下代码所示:

train(self, num_epochs, train_dataset, train_batch_size=64, eval_dataset=None, optimizer=None, save_interval_epochs=1, log_interval_steps=10, save_dir='output', pretrain_weights='IMAGENET', learning_rate=.025, warmup_steps=0, warmup_start_lr=0.0, lr_decay_epochs=(30, 60, 90), lr_decay_gamma=0.1, label_smoothing=None, early_stop=False, early_stop_patience=5, use_vdl=True)

其每项参数的定义如下所示:

num_epochs (int): 训练迭代轮数。
train_dataset (paddlex.dataset): 训练数据集。
train_batch_size (int): 训练数据batch大小。同时作为验证数据batch大小。默认为64。
eval_dataset (paddlex.dataset or None): 评估数据集。当该参数为None时,训练过程中不会进行模型评估。默认为None。
optimizer (paddle.optimizer.Optimizer): 优化器。当该参数为None时,使用默认优化器:paddle.optimizer.lr.PiecewiseDecay衰减策略,paddle.optimizer.Momentum优化方法。
save_interval_epochs (int): 模型保存间隔(单位:迭代轮数)。默认为1。
log_interval_steps (int): 训练日志输出间隔(单位:迭代步数)。默认为10。
save_dir (str): 模型保存路径。默认为’output’。
pretrain_weights (str or None): 若指定为’.pdparams’文件时,则从文件加载模型权重;若为字符串’IMAGENET’,则自动下载在ImageNet图片数据上预训练的模型权重;若为None,则不使用预训练模型。默认为’IMAGENET’。
learning_rate (float): 默认优化器的初始学习率。默认为0.025。
warmup_steps (int): 默认优化器的warmup步数,学习率将在设定的步数内,从warmup_start_lr线性增长至设定的learning_rate,默认为0。
warmup_start_lr(float): 默认优化器的warmup起始学习率,默认为0.0。
lr_decay_epochs (list): 默认优化器的学习率衰减轮数。默认为[30, 60, 90]。
lr_decay_gamma (float): 默认优化器的学习率衰减率。默认为0.1。
label_smoothing (float, bool or None): 是否使用标签平滑。若为float,表示标签平滑系数。若为True,使用系数为0.1的标签平滑。若为None或False,则不采用标签平滑。默认为None。
early_stop (bool): 是否使用提前终止训练策略。默认为False。
early_stop_patience (int): 当使用提前终止训练策略时,如果验证集精度在early_stop_patience个epoch内连续下降或持平,则终止训练。默认为5。
use_vdl (bool): 是否使用VisualDL进行可视化。默认为True。
resume_checkpoint (str): 恢复训练时指定上次训练保存的模型路径,例如output/mobilenetv3_small/best_model。若为None,则不会恢复训练。默认值为None。恢复训练需要将pretrain_weights设置为None。

我们采用如下代码定义PaddleX中内置的ResNet50模型,并调用内部的训练接口对其进行训练:

num_classes = len(train_dataset.labels) # 确定分类的类别数
model = pdx.cls.MobileNetV3_small(num_classes=num_classes)
save_dir = r'/home/aistudio/work/train/output/MobileNetV3_small'

model.train(num_epochs=10,
        train_dataset=train_dataset,
        train_batch_size=32,
        eval_dataset=eval_dataset,
        lr_decay_epochs=[4, 6, 8],
        save_dir=save_dir,
        use_vdl=True)

4.2 训练可视化

使用 BML CodeLab 左侧的可视化模块,在设置logdir处导入输出模型所在的文件夹,就可以进入VisualDL进行训练的实时可视化,上述模型可视化结果如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BXJA9ybL-1660123464635)(https://ai-studio-static-online.cdn.bcebos.com/0872c5f1c21441909e128742feda734f85bd547a21b6461c974a8e5811b7e4d4)]

五、模型的预测

要使我们训练出来的网络可以预测图片的类别,首先要保证输入的图片大小与训练集以及验证集相同,但是根据PaddleX 图像分类模型API中对predict接口的描述:

predict(self, img_file, transforms=None, topk=1)

我们得知,只要在训练过程中定义了eval_dataset,模型在保存时就会将预测时的图像处理流程保存在ResNet50.test_transforms和ResNet50.eval_transforms中。如未在训练时定义eval_dataset,那在调用预测predict接口时,用户需要再重新定义test_transforms传入给predict接口。

由于在模型训练时我们规定了对应的 eval_dataset,因此可以直接输入图片路径来分别对未标记图片数据进行分类结果预测。

首先,将test_dataset.zip解压,得到没有标签的数据:

!unzip /home/aistudio/data/data145073/test_dataset.zip -d /home/aistudio/work/test

导入训练好的模型,使用predict接口对解压后的test数据进行预测,对预测结果建立相应的文件夹并将获得标签的图片放入对应的文件夹中:

import paddlex as pdx
import os
import PIL

model = pdx.load_model('./work/train/output/MobileNetV3_small/best_model')

path = os.listdir(r'./work/test/test_images')
for p in path:
    if p[-4:] != '.jpg':
        continue
    image_dir = os.path.join(r'./work/test/test_images', p)
    print(image_dir)
    result = model.predict(image_dir)
    category = result[0]['category'] 
    img = PIL.Image.open(image_dir)
    draw = PIL.ImageDraw.Draw(img)
    font_size = img.size[0] // 10
    draw.text((10,10), category, 'red')
    pre_dir = os.path.join(r'./work/test/predict', category, p)
    try:
        img.save(pre_dir)
    except:
        os.makedirs(os.path.join(r'./work/test/predict', category))
        img.save(pre_dir)

我们可以直接进到./home/work/test/predict路径下看各个图片的分类情况,同时参考雾切凉宫——基于ResNet50模型的行车环境下天气时间分类
,也将数据的标签标注在了图片的左上角。

六、总结

本项目作为paddle框架的上手项目,目的为熟悉paddle以及BML CodeLab的使用,主要参考PaddleX API版的上手教程,按照其标准流程跑通,在文件结构整理部分,参考雾切凉宫——基于ResNet50模型的行车环境下天气时间分类
的相同项目。

参考:

[1] PaddleX API开发模式快速上手

[2] 雾切凉宫——基于ResNet50模型的行车环境下天气时间分类

[3] PaddleX 图像分类模型

[4] 图像分类ImageNet

[5] 图像分类数据增强文档

[6] 天气及时间分类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值