PaddleClas图像分类
徐仓仓 Lv3

概述

本文将讲解利用PaddleCals实现对图像进行分类的任务,利用AI Studio平台训练,并通过猫十二分类例子讲解如何进行训练与预测。

版本

  • PaddlePaddle 2.1.2
  • PaddleClas 2.3

下载PaddleClas

此时可以将PaddleClas下载到项目中。

1
!git clone https://gitee.com/paddlepaddle/PaddleClas/ --depth=1

预处理

1.解压数据集

1
2
# 解压缩数据集
!unzip -qoa data/data8136/cat_data_sets_models.zip -d data/

2.划分数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import os
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np

def break_data(target, rate=0.2):
origin_dataset = pd.read_csv("/home/aistudio/data/data_sets/cat_12/train_list.txt", delimiter="\t", header=None) # 加入参数
# train_data, test_data = train_test_split(origin_dataset, test_size=rate)
train_data,eval_data=train_test_split(origin_dataset, test_size=rate)
train_filename = os.path.join(target, 'train.txt')
# test_filename = os.path.join(target, 'test.txt')
eval_filename = os.path.join(target, 'eval.txt')

train_data.to_csv(train_filename, index=False, sep="\t", header=None)
# test_data.to_csv(test_filename, index=False, sep="\t", header=None)
eval_data.to_csv(eval_filename, index=False, sep="\t", header=None)


if __name__ == '__main__':
break_data(target='data', rate=0.2)

3.通道转化

由于图片中存在一些非RGB格式的图片,会影响训练,因此进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#导入需要的包
import os
import random
import json
import cv2
import numpy as np
from PIL import Image
import paddle
import matplotlib.pyplot as plt
## 转换4通道为3通道
def proc_img(src):
for root, dirs, files in os.walk(src):
if '__MACOSX' in root:continue
for file in files:
src=os.path.join(root,file)
img=Image.open(src)
## 转换4通道为3通道
if img.mode != 'RGB':
img = img.convert('RGB')
img.save(src)
print(src)


if __name__=='__main__':
proc_img("data/data_sets/cat_12/cat_12_train")
proc_img("data/data_sets/cat_12/cat_12_test")

训练

1.修改bug

由于PaddleClas2.3版本读数据存在bug,因此修改如下文件
目录:\ppcls\data\dataloader\imagenet_dataset.py
注释:

  • assert os.path.exists(self._cls_path)
  • assert os.path.exists(self._img_path)
    添加:
  • self._cls_path=os.path.join(self._img_root,self._cls_path)
    同时修改with open()as fd:中的内容如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class ImageNetDataset(CommonDataset):
    def _load_anno(self, seed=None):
    # 会对目录进行检测,如果cls_path使用相对目录,就会报错,在此注释掉,并修改为self._cls_path=os.path.join(self._img_root,self._cls_path)

    self.images = []
    self.labels = []

    with open(self._cls_path) as fd:
    lines = fd.readlines()
    if seed is not None:
    np.random.RandomState(seed).shuffle(lines)
    for l in lines:
    # tab分割
    # l = l.strip().split(" ")
    l = l.strip().split("\t")
    self.images.append(os.path.join(self._img_root, l[0]))
    self.labels.append(int(l[1]))
    # 不需要判断这个
    # assert os.path.exists(self.images[-1])

    2.修改配置文件

    选择PaddleClas/ppcls/configs/ImageNet/ 中的模型,这里以ResNet为例,选择其中的ResNet50_vd.yaml配置文件,主要修改参数如下:
  • class_num: 12
    Train和Eval下均需修改
  • image_root: /home/aistudio/data/data_sets/cat_12/
  • cls_label_path: /home/aistudio/data/eval.txt

3.配置说明

3.1 全局配置(Global)
参数名字 具体含义 默认值 可选值
checkpoints 断点模型路径,用于恢复训练 null str
pretrained_model 预训练模型路径 null str
output_dir 保存模型路径 “./output/“ str
save_interval 每隔多少个epoch保存模型 1 int
eval_during_train 是否在训练时进行评估 True bool
eval_interval 每隔多少个epoch进行模型评估 1 int
epochs 训练总epoch数 int
print_batch_step 每隔多少个mini-batch打印输出 10 int
use_visualdl 是否是用visualdl可视化训练过程 False bool
image_shape 图片大小 [3,224,224] list, shape: (3,)
save_inference_dir inference模型的保存路径 “./inference” str
eval_mode eval的模式 “classification” “retrieval”
3.2 结构(Arch)
参数名字 具体含义 默认值 可选值
name 模型结构名字 ResNet50 PaddleClas提供的模型结构
class_num 分类数 1000 int
pretrained 预训练模型 False bool, str
3.3 损失函数(Loss)
参数名字 具体含义 默认值 可选值
CELoss 交叉熵损失函数 —— ——
CELoss.weight CELoss的在整个Loss中的权重 1.0 float
CELoss.epsilon CELoss中label_smooth的epsilon值 0.1 float,0-1之间
3.4 优化器(Optimizer)
参数名字 具体含义 默认值 可选值
name 优化器方法名 “Momentum” “RmsProp”等其他优化器
momentum momentum值 0.9 float
lr.name 学习率下降方式 “Cosine” “Linear”、”Piecewise”等其他下降方式
lr.learning_rate 学习率初始值 0.1 float
lr.warmup_epoch warmup轮数 0 int,如5
regularizer.name 正则化方法名 “L2” [“L1”, “L2”]
regularizer.coeff 正则化系数 0.00007 float

4.开始训练

1
2
# 使用以下命令进入项目目录
%cd PaddleClas/
1
2
3
4
5
# GPU设置
!export CUDA_VISIBLE_DEVICES=0

# -o Arch.pretrained=True 使用预训练模型,当选择为True时,预训练权重会自动下载到本地
!python tools/train.py -c /home/aistudio/PaddleClas/ppcls/configs/ImageNet/ResNet/ResNet50_vd.yaml -o Arch.pretrained=True

使用多卡训练

1
2
3
4
5
!export CUDA_VISIBLE_DEVICES=0,1,2,3
!python3 -m paddle.distributed.launch \
--gpus="0,1,2,3" \
tools/train.py \
-c /home/aistudio/ResNet50_vd.yaml -o Arch.pretrained=True

预测

输入以下命令进行单张图片预测:

1
2
# 预测
!python3 tools/infer.py -c /home/aistudio/ResNet50_vd.yaml -o Infer.infer_imgs=/home/aistudio/data/data_sets/cat_12/cat_12_test/ou9Ik17GtHSThRCDLZm3f6vB8ybQ4xsl.jpg -o Global.pretrained_model=output/ResNet50_vd/best_model

输入以下命令进行批量图片预测,并重定向到output.txt文件中。

1
2
# 预测
!python3 tools/infer.py -c /home/aistudio/ResNet50_vd.yaml -o Infer.infer_imgs=/home/aistudio/data/data_sets/cat_12/cat_12_test/ -o Global.pretrained_model=output/ResNet50_vd/best_model > output.txt

输入以下命令生成提交的csv文件格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import ast
import re

with open("output.txt") as f:
ftxt = f.read()

pattern = r"{'class_ids':.*?}"
pre_results = re.findall(pattern, ftxt)
print(len(pre_results))

pre_data = []
for pre_result in pre_results:
pre_dict = ast.literal_eval(pre_result) # ["class_ids", "scores", "file_name", "label_names"]
pre_data.append([pre_dict["file_name"].split("/")[-1],\
pre_dict["class_ids"][0], pre_dict["scores"][0]])

columns = ["img_path", "label", "scores"]
pre_df = pd.DataFrame(data=pre_data,
index=range(len(pre_data)),
columns=columns)

pre_df.drop(columns=['scores'],inplace=True) # 删除 scores 列
pre_df.sort_values(["img_path"], inplace=True) # 排序
pre_df.to_csv('submission.csv',index=None,header=None)
 Comments