一、问题背景
基于Caltech数据集的图像分类,Caltech101包含101个目标类+背景类,每种类别大约40到800个图像,训练集总计7999图像。本次试题需要图片为输入,通过课程学习的分类方法(支持向量机、深度神经网络、卷积神经网络等)从中识别该图像属于哪一个类别。
二、代码实现
2.1数据预处理
2.1.1解压数据集
!unzip /home/aistudio/data/data146107/dataset.zip -d /home/aistudio/data
2.1.2导入所需的包
# 导入需要的包
import paddle
import os
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import sys
import pickle
from paddle.vision.transforms import ToTensor
import paddle.nn.functional as F
print("本教程基于Paddle的版本号为:"+paddle.__version__)
# 本方案基于paddlepaddle2.2.2实现
2.1.3划分好数据集
from sklearn.utils import shuffle
total_list = []
# 打开 train.txt 文件并读取内容
f = open('/home/aistudio/data/dataset/train.txt', 'r', encoding='utf-8')
total_list = f.readlines()
f.close()
# 随机打乱数据
total_list = shuffle(total_list, random_state=100)
# 确定训练集和验证集的长度
train_len = int(0.85 * 7999)
# 划分训练集和验证集
train_list = total_list[:train_len]
val_list = total_list[train_len:]
# 打开 train1.txt 和 val.txt 文件用于写入
f1 = open('/home/aistudio/data/dataset/train1.txt', 'w', encoding='utf-8')
f2 = open('/home/aistudio/data/dataset/val.txt', 'w', encoding='utf-8')
# 将训练集写入 train1.txt 文件
for line in train_list:
f1.write(line)
# 将验证集写入 val.txt 文件
for line in val_list:
f2.write(line)
# 关闭文件
f1.close()
f2.close()
2.1.4提取标签label
# 打开 label.txt 文件用于写入
f3 = open('/home/aistudio/data/dataset/label.txt', 'w', encoding='utf-8')
# 打开 class.txt 文件用于读取
f = open('/home/aistudio/data/dataset/class.txt', 'r', encoding='utf-8')
# 逐行读取 class.txt 文件内容
for line in f.readlines():
# 去除每行两端的空白符并按制表符 '\t' 分割字符串,获取标签名称和标签ID
label_name, label_id = line.strip().split('\t')
# 将标签名称写入 label.txt 文件,并在每个标签后添加换行符
f3.write(label_name + '\n')
# 关闭 label.txt 文件
f3.close()
2.1.5安装paddlex(最新版)
!pip install paddlex
2.1.6数据增强
from paddlex import transforms as T
# 训练集数据变换列表
train_transforms = T.Compose([
T.RandomHorizontalFlip(), # 随机水平翻转
T.RandomVerticalFlip(), # 随机垂直翻转
T.MixupImage(alpha=1.5, beta=1.5, mixup_epoch=-1), # Mixup增强,alpha和beta调整混合强度,mixup_epoch设置为-1表示在所有训练时期都应用Mixup
T.RandomBlur(prob=0.1), # 以0.1的概率对图像进行随机模糊处理
T.RandomDistort(), # 随机扭曲图像
T.Normalize(), # 图像归一化处理
T.Resize(224) # 调整图像大小为224x224像素
])
# 评估集数据变换列表
eval_transforms = T.Compose([
T.Normalize(), # 图像归一化处理
T.Resize(224) # 调整图像大小为224x224像素
])
如果这一步发生报错请将pyarrow包降版本为0.17.0版本或更高一点点的版本。0.17.0版本测试是可以通过的。
2.1.7构建数据集
import paddlex as pdx
# 创建训练集
train_dataset = pdx.datasets.ImageNet(
data_dir='/home/aistudio/data/dataset/images/', # 数据集存储路径
file_list='/home/aistudio/data/dataset/train1.txt', # 训练集文件列表路径
label_list='/home/aistudio/data/dataset/label.txt', # 标签文件路径
transforms=train_transforms, # 训练集数据变换方式
shuffle=True # 是否对数据进行随机打乱
)
# 创建验证集
eval_dataset = pdx.datasets.ImageNet(
data_dir='/home/aistudio/data/dataset/images/', # 数据集存储路径
file_list='/home/aistudio/data/dataset/val.txt', # 验证集文件列表路径
label_list='/home/aistudio/data/dataset/label.txt', # 标签文件路径
transforms=eval_transforms # 验证集数据变换方式
)
# 创建总数据集(包含训练集和验证集)
total_dataset = pdx.datasets.ImageNet(
data_dir='/home/aistudio/data/dataset/images/', # 数据集存储路径
file_list='/home/aistudio/data/dataset/train.txt', # 总数据集文件列表路径
label_list='/home/aistudio/data/dataset/label.txt', # 标签文件路径
transforms=train_transforms, # 总数据集数据变换方式
shuffle=True # 是否对数据进行随机打乱
)
2.2模型训练
2.2.1设置超参数并训练
num_classes = len(train_dataset.labels) # 获取数据集的类别数量,用于模型的输出类别数
# 使用 PaddleX 提供的 ResNet101_vd_ssld 模型,传入类别数作为参数
model = pdx.cls.ResNet101_vd_ssld(num_classes=num_classes)
# 对模型进行训练
model.train(num_epochs=50, # 训练的轮数
train_dataset=train_dataset, # 训练集数据
train_batch_size=64, # 训练时的批量大小
eval_dataset=eval_dataset, # 验证集数据
lr_decay_epochs=[10, 20, 30], # 学习率衰减的时期
save_dir='output/resnet101_ssld', # 模型和日志保存的路径
label_smoothing=True, # 是否使用标签平滑(减少过拟合)
use_vdl=True) # 是否使用可视化工具进行训练过程的监控和记录
2.2.2测试验证集效果
model = pdx.load_model('output/resnet101_ssld//best_model') # 导入效果最好的模型
model.evaluate(eval_dataset, batch_size=1, return_details=True) # 验证集结果
2.2.3测试全部数据集
# 对模型进行更多轮次的训练(总共 15 轮)
model.train(num_epochs=15, # 训练的轮数
train_dataset=total_dataset, # 使用全部数据集进行训练
train_batch_size=64, # 训练时的批量大小
eval_dataset=eval_dataset, # 验证集数据
lr_decay_epochs=[4, 6, 8], # 学习率衰减的时期
save_dir='output/resnet101_ssld1', # 模型和日志保存的路径
label_smoothing=True, # 是否使用标签平滑(减少过拟合)
use_vdl=True) # 是否使用可视化工具进行训练过程的监控和记录
2.2.4预测测试集
# 导入最佳模型以进行预测
model = pdx.load_model('output/resnet101_ssld/best_model') # 加载第一次训练最佳模型
#model = pdx.load_model('output/resnet101_ssld1/best_model') # 加载第二次训练最佳模型
test_path = "/home/aistudio/data/dataset/images/" # 测试集图片路径
test_files = []
# 读取测试集文件列表
f = open('/home/aistudio/data/dataset/test.txt', 'r', encoding='utf-8')
for line in f.readlines():
test_files.append(test_path + line.strip()) # 将测试集文件路径添加到列表中
f.close()
# 使用模型进行预测
result = model.predict(img_file=test_files, transforms=eval_transforms) # 对测试集图片进行预测
print("Predict Result:\n", result) # 打印预测结果
2.3.5将结果写入result.txt文件
f = open('/home/aistudio/result.txt', 'w', encoding='utf-8') # 打开文件用于写入预测结果
k = 0
# 遍历预测结果并写入文件
for d in result:
img_name = test_files[k].split('/')[-1] # 获取图片文件名
f.write(img_name + '\t' + str(d[0]['category_id']) + '\n') # 写入图片名和对应的预测类别ID
k += 1
f.close() # 关闭文件
三、项目地址
github:百度松果飞浆大作业--图像分类
paddlepaddle:百度松果飞浆大作业--图像分类