★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>

500种鸟类分类是一个相对较简单的细粒度分类问题,我通过PP-HGNet模型训练能够达到top1指标98.6%,top5指标99.88%,能够达到很好的分类效果,是一个比较成功的案例。

1. 项目背景

细粒度图像分类问题是对大类下的子类进行识别。细粒度图像分析任务相对通用图像(General/Generic Images)任务的区别和难点在于其图像所属类别的粒度更为精细。

细粒度图像分类无论在工业界还是学术界都有着广泛的研究需求与应用场景。与之相关的研究课题主要包括识别不同种类的鸟、狗、花、车、飞机等。在实际生活中,识别不同的子类别又存在着巨大的应用需求。例如, 在生态保护中, 有效识别不同种类的生物,是进行生态研究的重要前提。如果能够借助于计算机视觉的技术, 实现低成本的细粒度图像识别, 那么无论对于学术界, 还是工业界而言, 都有着非常重要的意义。

由于分类的粒度很小,细粒度图像分类非常困难,在某些类别上甚至专家都难以区分。主要原因有三:

  • 子类之间差异细微:只在某个局部上有细微差异,如狗的眼睛。
  • 子类内部差异巨大:如姿态、背景带来的差异。
  • 受视角、背景、遮挡等因素影响较大。

2. 数据集介绍

该数据集来源于Kaggle,现已上传至AI Studio。数据集地址

  • 该数据集总共包含80085张训练图像,2500张测试图像(每个物种5张图像)和2500张验证图像(每个物种5张图像)。
  • 每个图像中只有一只鸟,并且鸟通常至少占据图像中 50% 的像素。所有图像均为原始图像,并非通过增强创建。
  • 所有图像均为 jpg 格式的 224 X 224 X 3 彩色图像。数据集包括训练集、测试集和验证集。每个包含475个子目录,每种鸟类一个。
  • 该数据集还包括birds.csv文件。此 cvs 文件包含 5 列。filepaths列包含图像文件的相对文件路径。labels列包含与图像文件关联的鸟类名称。scientific name列包含图像的拉丁学名。data set列表示文件路径所在的数据集(train/test/valid)。class_id列包含与图像文件的类关联的类索引值。
  • 注意:该数据集不能直接使用paddleclas开发套件训练,需要创建列表文件和标签文件。

部分数据集图片如下所示:

3. 环境准备

克隆 PaddleClas:

!git clone https://gitee.com/PaddlePaddle/PaddleClas.git -b release/2.5

安装 PaddleClas 及其 Python 依赖库:

!pip install paddleclas

4. 数据集预处理

Step01: 解压数据集

!unzip /home/aistudio/data/data199247/archive.zip -d /home/aistudio/work/

Step02: 生成paddleclas所需的txt文件

列表文件获取思路如下:

  • 首先取出csv文件中的指定列,打乱样本顺序;
  • 然后通过判断data set列的值判断是训练集、验证集和测试集;
  • 最后创建三个列表文件,根据要求的格式写入txt文件中。
import pandas as pd
from sklearn.utils import shuffle

filename = "/home/aistudio/work/birds.csv"
data = pd.read_csv("/home/aistudio/work/birds.csv",usecols=[0,1,3])
data = shuffle(data) 
total = len(open(filename).readlines())
print(total)
train_list = "/home/aistudio/work/train_list.txt"
valid_list = "/home/aistudio/work/valid_list.txt"
test_list = "/home/aistudio/work/test_list.txt"
train_file = open(train_list, "w", encoding='utf-8')
valid_file = open(valid_list, "w", encoding='utf-8')
test_file = open(test_list, "w", encoding='utf-8')
for i in range(0, total-1):
    if data.iloc[i]["data set"] == "train":
        train_file.write(data.iloc[i]["filepaths"]+" "+str(data.iloc[i]["class id"])+"\n")
    if data.iloc[i]["data set"] == "valid":
        valid_file.write(data.iloc[i]["filepaths"]+" "+str(data.iloc[i]["class id"])+"\n")
    if data.iloc[i]["data set"] == "test":
        test_file.write(data.iloc[i]["filepaths"]+" "+str(data.iloc[i]["class id"])+"\n")
train_file.close()
valid_file.close()
test_file.close()

标签映射文件获取思路如下:

  • 首先取出csv文件中的指定列;
  • 然后消除重复值;
  • 最后创建标签映射文件,根据要求的格式写入txt文件中。
label = pd.read_csv('/home/aistudio/work/birds.csv',usecols=[0,2])
label.drop_duplicates(subset=['class id','labels'],keep='first',inplace=True)
label_list = "/home/aistudio/work/label_list.txt"
label_file = open(label_list, "w", encoding='utf-8')
for i in range(500):
    label_file.write(str(label.iloc[i]["class id"])+" "+label.iloc[i]["labels"]+"\n")
label_file.close()

Step3: 将数据集移动到/home/aistudio/PaddleClas/dataset目录下

!mv /home/aistudio/work/* /home/aistudio/PaddleClas/dataset/

5. 代码实现

5.1 模型简介

PP-HGNet(High Performance GPU Net) 是百度飞桨视觉团队自研的更适用于 GPU 平台的高性能骨干网络,该网络在 VOVNet 的基础上使用了可学习的下采样层(LDS Layer),融合了 ResNet_vd、PPHGNet 等模型的优点,该模型在 GPU 平台上与其他 SOTA 模型在相同的速度下有着更高的精度。在同等速度下,该模型高于 ResNet34-D 模型 3.8 个百分点,高于 ResNet50-D 模型 2.4 个百分点,在使用百度自研 SSLD 蒸馏策略后,超越 ResNet50-D 模型 4.7 个百分点。与此同时,在相同精度下,其推理速度也远超主流 VisionTransformer 的推理速度。

PP-HGNet 作者针对 GPU 设备,对目前 GPU 友好的网络做了分析和归纳,尽可能多的使用 3x3 标准卷积(计算密度最高)。在此将 VOVNet 作为基准模型,将主要的有利于 GPU 推理的改进点进行融合。从而得到一个有利于 GPU 推理的骨干网络,同样速度下,精度大幅超越其他 CNN 或者 VisionTransformer 模型。

PP-HGNet 骨干网络的整体结构如下:

其中,PP-HGNet是由多个HG-Block组成,HG-Block的细节如下:

5.2 模型训练

ERROR1:路径存在空格

ValueError: invalid literal for int() with base 10: 'FIREBACK/104.jpg'

SOLUTION1:

  • 首先替换文件夹名字中的空格
  • 然后替换列表文件中的空格,具体操作时只需要在前面的代码中加上.replace(" ", “_”)即可

代码如下:

%cd /home/aistudio/PaddleClas/dataset/train
!rename "s/\s/_/g" *
%cd /home/aistudio/PaddleClas/dataset/valid
!rename "s/\s/_/g" *
%cd /home/aistudio/PaddleClas/dataset/test
!rename "s/\s/_/g" *
filename = "/home/aistudio/work/birds.csv"
data = pd.read_csv("/home/aistudio/work/birds.csv",usecols=[0,1,3])
data = shuffle(data) 
total = len(open(filename).readlines())
print(total)
train_list = "/home/aistudio/work/train_list.txt"
valid_list = "/home/aistudio/work/valid_list.txt"
test_list = "/home/aistudio/work/test_list.txt"
train_file = open(train_list, "w", encoding='utf-8')
valid_file = open(valid_list, "w", encoding='utf-8')
test_file = open(test_list, "w", encoding='utf-8')
for i in range(0, total-1):
    if data.iloc[i]["data set"] == "train":
        train_file.write(data.iloc[i]["filepaths"].replace(" ", "_")+" "+str(data.iloc[i]["class id"])+"\n")
    if data.iloc[i]["data set"] == "valid":
        valid_file.write(data.iloc[i]["filepaths"].replace(" ", "_")+" "+str(data.iloc[i]["class id"])+"\n")
    if data.iloc[i]["data set"] == "test":
        test_file.write(data.iloc[i]["filepaths"].replace(" ", "_")+" "+str(data.iloc[i]["class id"])+"\n")
train_file.close()
valid_file.close()
test_file.close()
85086
label = pd.read_csv('/home/aistudio/work/birds.csv',usecols=[0,2])
label.drop_duplicates(subset=['class id','labels'],keep='first',inplace=True)
label_list = "/home/aistudio/work/label_list.txt"
label_file = open(label_list, "w", encoding='utf-8')
for i in range(500):
    label_file.write(str(label.iloc[i]["class id"])+" "+label.iloc[i]["labels"].replace(" ", "_")+"\n")
label_file.close()

[注意]: 记得加载预训练模型,不然收敛会很慢。

%cd /home/aistudio/PaddleClas
!python tools/train.py -c ppcls/configs/ImageNet/PPHGNet/PPHGNet_small.yaml

损失函数如图所示:

5.3 模型评估

训练好模型之后,可以通过以下命令实现对模型指标的评估。

%cd /home/aistudio/PaddleClas
!python tools/eval.py \
    -c ppcls/configs/ImageNet/PPHGNet/PPHGNet_small.yaml \
    -o Global.pretrained_model=output/PPHGNet_small/best_model

我们可以看到模型的top1指标为98.6%,top5指标为99.88%。

  • [Avg]CELoss: 0.26817, loss: 0.26817, top1: 0.98600, top5: 0.99880

5.4 模型预测

模型训练完成之后,可以加载训练得到的预训练模型,进行模型预测。在模型库的 tools/infer.py 中提供了完整的示例,只需执行下述命令即可完成模型预测:

!python tools/infer.py \
    -c ppcls/configs/ImageNet/PPHGNet/PPHGNet_small.yaml \
    -o Global.pretrained_model=output/PPHGNet_small/best_model

我们可以看到模型在测试集上也有不错的表现力。

  • [{‘class_ids’: [0, 249, 44, 216, 31], ‘scores’: [0.8234, 0.01828, 0.00695, 0.00503, 0.00361], ‘file_name’: ‘./dataset/test/ABBOTTS_BABBLER/1.jpg’, ‘label_names’: [‘ABBOTTS_BABBLER’, ‘GREAT_XENOPS’, ‘AZARAS_SPINETAIL’, ‘FASCIATED_WREN’, ‘ANTBIRD’]}]

6. 总结提高

本项目是一个相对较简单的细粒度分类问题,通过PP-HGNet模型训练能够达到top1指标98.6%,top5指标99.88%。该问题的主要难点在于数据集的处理,我们从Kaggle获取到的原数据集不能直接使用PaddleClas训练,需要我们通过Python编写代码生成列表文件和标签文件,需要一定的Python基础,同时需要注意的是,文件路径不能存在空格,希望fork的小伙伴不要二次踩坑哦。

作者简介:Submerge. 江苏某大学大三学生 人工智能专业 主页链接 欢迎互关!

飞桨导师:刘建建 JavaRoom 在此感谢。
此文章为转载
原文连接

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐