图像分类竞赛全流程实战
文章目录
本博客将以柠檬品相分类比赛为例,为大家详细介绍下图像分类比赛的完整流程。为大家提供从数据处理,到模型搭建,损失函数、优化算法选择,学习率调整策略到模型训练,以及推理输出一条龙服务。每个模块都有很多tricks,在这里我会逐一为大家进行理论介绍以及相应的代码实战。
任务分析
图像分类竞赛全流程工具
- 编程语言
python
- 炼丹框架
PaddlePaddle2.0
- 图像预处理库
OpenCV
PIL(pillow)
- 通用库
Numpy
Pandas
Scikit-Learn
Matplotlib
图像分类比赛的一般解题流程
- 数据EDA (Pandas、Matplotlib)
- 数据预处理 (OpenCV、PIL、Pandas、Numpy、Scikit-Learn)
- 根据赛题任务定义好读取方法,即Dataset和Dataloader(PaddlePaddle2.0)
- 选择一个图像分类模型进行训练 (PaddlePaddle2.0)
- 对测试集进行测试并提交结果(PaddlePaddle2.0、Pandas)
# 导入所需要的库
from sklearn.utils import shuffle
import os
import pandas as pd
import numpy as np
from PIL import Image
import paddle
import paddle.nn as nn
from paddle.io import Dataset
import paddle.vision.transforms as T
import paddle.nn.functional as F
from paddle.metric import Accuracy
import warnings
warnings.filterwarnings("ignore")
数据解压
!unzip -oq data/data72793/lemon_homework.zip -d data
!unzip -oq data/lemon_homework/lemon_lesson.zip -d data/lemon_homework
!cd data/lemon_homework/lemon_lesson/ && unzip -oq train_images.zip && unzip -oq test_images.zip
EDA(Exploratory Data Analysis)与数据预处理
数据EDA
探索性数据分析(Exploratory Data Analysis,简称EDA),是指对已有的数据(原始数据)进行分析探索,通过作图、制表、方程拟合、计算特征量等手段探索数据的结构和规律的一种数据分析方法。一般来说,我们最初接触到数据的时候往往是毫无头绪的,不知道如何下手,这时候探索性数据分析就非常有效。
对于图像分类任务,我们通常首先应该统计出每个类别的数量,查看训练集的数据分布情况。通过数据分布情况分析赛题,形成解题思路。(洞察数据的本质很重要。)
数据分析的一些建议
1、写出一系列你自己做的假设,然后接着做更深入的数据分析。
2、记录自己的数据分析过程,防止出现遗忘。
3、把自己的中间的结果给自己的同行看看,让他们能够给你一些更有拓展性的反馈、或者意见。(即open to everybody)
4、可视化分析结果
# 数据EDA
df = pd.read_csv('data/lemon_homework/lemon_lesson/train_images.csv')
d = df['class_num'].hist().get_figure()
# d.savefig('2.jpg')
print(d)
Figure(432x288)
数据集样本数量不平衡问题
label shuffling
首先对原始的图像列表,按照标签顺序进行排序;
然后计算每个类别的样本数量,并得到样本最多的那个类别的样本数。
根据这个最多的样本数,对每类都产生一个随机排列的列表;
然后用每个类别的列表中的数对各自类别的样本数求余,得到一个索引值,从该类的图像中提取图像,生成该类的图像随机列表;
然后把所有类别的随机列表连在一起,做个Random Shuffling,得到最后的图像列表,用这个列表进行训练。
# 读取数据
train_images = pd.read_csv('data/lemon_homework/lemon_lesson/train_images.csv', usecols=['id','class_num']) # 读取文件名和类别
# labelshuffling
def labelShuffling(dataFrame, groupByName='class_num'):
groupDataFrame = dataFrame.groupby(by=[groupByName])
labels = groupDataFrame.size()
print("length of label is ", len(labels))
maxNum = max(labels)
lst = pd.DataFrame()
for i in range(len(labels)):
print("Processing label :", i)
tmpGroupBy = groupDataFrame.get_group(i)
createdShuffleLabels = np.random.permutation(np.array(range(maxNum))) % labels[i] # 随机排列组合
print("Num of the label is : ", labels[i])
lst=lst.append(tmpGroupBy.iloc[createdShuffleLabels], ignore_index=True)
# print("Done")
# lst.to_csv('test1.csv', index=False)
return lst
# 划分训练集和校验集 8:2
all_size = len(train_images)
print("训练集大小:", all_size)
train_size = int(all_size * 0.8)
train_image_list = train_images[:train_size]
val_image_list = train_images[train_size:]
df = labelShuffling(train_image_list)
df = shuffle(df)
train_image_path_list = df['id'].values
label_list = df['class_num'].values
label_list = paddle.to_tensor(label_list, dtype='int64')
train_label_list = paddle.nn.functional.one_hot(label_list, num_classes=4)
val_image_path_list = val_image_list['id'].values
val_label_list = val_image_list['class_num'].values
val_label_list = paddle.to_tensor(val_label_list, dtype='int64')
val_label_list = paddle.nn.functional.one_hot(val_label_list, num_classes=4)
训练集大小: 1102
length of label is 4
Processing label : 0
Num of the label is : 321
Processing label : 1
Num of the label is : 207
Processing label : 2
Num of the label is : 181
Processing label : 3
Num of the label is : 172
# 定义数据预处理
data_transforms = T.Compose([
T.RandomResizedCrop(224, scale=(0.8, 1.2), ratio=(3. / 4, 4. / 3), interpolation='bilinear'),
T.RandomHorizontalFlip(),
T.RandomVerticalFlip(),
T.