本次将带领大家进行自定义数据集教程,并完整的走完整个项目流程。
# 解压数据集,大家此处可以视自己的情况决定是不是要重新解压。
!unzip -q data/data42610/foods.zip
此部分首先对数据集进行简单的整理,在food_data.csv中写入图像路径,以及对应的标签。
import os
all_file_dir = 'foods'
# f = open(r'train.txt', 'w')
img_list = []
label_list = []
label_id = 0
class_list = [c for c in os.listdir(all_file_dir) if os.path.isdir(os.path.join(all_file_dir, c))]
# print(class_list)
for class_dir in class_list:
image_path_pre = os.path.join(all_file_dir, class_dir)
for img in os.listdir(image_path_pre):
# print(img)
# f.write("{0}\t{1}\n".format(os.path.join(image_path_pre, img), label_id))
img_list.append(os.path.join(image_path_pre, img))
label_list.append(label_id)
label_id += 1
生成包含数据集信息的csv文件。
import pandas as pd
import numpy as np
img_df = pd.DataFrame(img_list)
label_df = pd.DataFrame(label_list)
img_df.columns = ['images']
label_df.columns = ['label']
df = pd.concat([img_df, label_df], axis=1)
df = df.reindex(np.random.permutation(df.index))
df.to_csv('food_data.csv', index=0)
# 读取数据
df = pd.read_csv('food_data.csv')
image_path_list = df['images'].values
label_list = df['label'].values
# 划分训练集和校验集
all_size = len(image_path_list)
train_size = int(all_size * 0.8)
train_image_path_list = image_path_list[:train_size]
train_label_list = label_list[:train_size]
val_image_path_list = image_path_list[train_size:]
val_label_list = label_list[train_size:]
import numpy as np
from PIL import Image
from paddle.io import Dataset
import paddle.vision.transforms as T
import paddle as pd
class MyDataset(Dataset):
"""
步骤一:继承paddle.io.Dataset类
"""
def __init__(self, image, label, transform=None):
"""
步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集
"""
super(MyDataset, self).__init__()
# imgs = []
# f = open(txt, 'r')
# for line in f:
# line = line.strip('\n')
# line = line.rstrip('\n')
# words = line.split()
# imgs.append((words[0], int(words[1])))
imgs = image
labels = label
self.labels = labels
self.imgs = imgs
self.transform = transform
# self.loader = loader
def __getitem__(self, index): # 这个方法是必须要有的,用于按照索引读取每个元素的具体内容
fn = self.imgs
label = self.labels
# fn是图片path #fn和label分别获得imgs[index]也即是刚才每行中word[0]和word[1]的信息
for im,la in zip(fn, label):
img = Image.open(im)
img = img.convert("RGB")
img = np.array(img)
label = np.array([la]).astype(dtype='int64')
# 按照路径读取图片
if self.transform is not None:
img = self.transform(img)
# 数据标签转换为Tensor
return img, label
# return回哪些内容,那么我们在训练时循环读取每个batch时,就能获得哪些内容
# ********************************** #使用__len__()初始化一些需要传入的参数及数据集的调用**********************
def __len__(self):
# 这个函数也必须要写,它返回的是数据集的长度,也就是多少张图片,要和loader的长度作区分
return len(self.imgs)
import paddle
from paddle.metric import Accuracy
from paddle.vision.models import resnet18
import warnings
warnings.filterwarnings("ignore")
import warnings
warnings.filterwarnings("ignore")
import paddle.vision.transforms as T
transform = T.Compose([
T.Resize([224, 224]),
T.ToTensor(),
T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
# T.Transpose(),
])
train_dataset = MyDataset(image=train_image_path_list, label=train_label_list ,transform=transform)
train_loader = paddle.io.DataLoader(train_dataset, places=paddle.CPUPlace(), batch_size=8, shuffle=True)
# build model
model = resnet18(pretrained=True, num_classes=102, with_pool=True)
model = paddle.Model(model)
optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())
此步骤对模型进行训练,并保存为推理模型。(和checkpoint不同,注意区分)。
此处仅进行了两次迭代,大家有兴趣可以自行调整迭代次数。
# 配置模型
model.prepare(
optim,
paddle.nn.CrossEntropyLoss(),
Accuracy(topk=(1, 2))
)
model.fit(train_loader,
epochs=2,
verbose=1,
)
model.evaluate(train_dataset, batch_size=8, verbose=1)
model.save('inference_model', False)
在模型预测推理中,最后生成的CSV文件是一个较为通用的竞赛提交文件,大家可以根据自己的需要进行相应的更改。也算是一个小小的福利吧。
import warnings
warnings.filterwarnings('ignore')
import sys
import paddle.fluid as fluid
import paddle
import numpy as np
import os
import pandas as pd
paddle.enable_static()
def load_img(img):
is_color = True
resize_size = 320
crop_size = 100 # 剪切尺寸,最后图片的size是这个值,不是resize_size
img = paddle.dataset.image.load_image(file=img, is_color=is_color)
img = paddle.dataset.image.simple_transform(im=img,
resize_size=resize_size, crop_size=crop_size,
is_color=is_color, is_train=False)
img = img.astype('float32') / 255.0
return img
def pred_data(path_img_test):
# 构建执行器
USE_GPU = False
place = fluid.CUDAPlace(0) if USE_GPU else fluid.CPUPlace() # 使用CPU执行训练
infer_exe = fluid.Executor(place)
inference_scope = fluid.core.Scope()
# 载入model
with fluid.scope_guard(scope=inference_scope):
currentpath = os.path.dirname(sys.argv[0])
[inference_program,
feed_target_names,
fetch_targets] = fluid.io.load_inference_model(
dirname=os.path.join(currentpath, 'model_'), executor=infer_exe)
test_imgs_dir = path_img_test
img_data, img_paths, img_names = [], [], []
for img_name in os.listdir(test_imgs_dir):
img_path = os.path.join(test_imgs_dir, img_name)
img_paths.append(img_path)
img_data.append(load_img(img_path))
img_names.append(img_name.split('.')[0])
img_data = np.array(img_data).astype("float32")
result = infer_exe.run(program=inference_program,
feed={
feed_target_names[0]: img_data},
fetch_list=fetch_targets)
infer_label = [np.argmax(x) for x in result[0]]
class_dict = {
0: 'neg', 1: 'pos'}
pred_class = []
for i in infer_label:
pred_class.append(class_dict[i])
submit = pd.DataFrame({
'id': img_names, 'label': pred_class})
return submit
def main(path_img_test, path_submit):
# 预测图片
result = pred_data(path_img_test)
# 写出预测结果
result.to_csv(path_submit, index=None, encoding='utf-8')
if __name__ == "__main__":
path_img_test = 'foods/beef_carpaccio'
path_submit = 'test.csv'
main(path_img_test, path_submit)
本次实践主要讲解一下如何自定义数据集,并对一个图像分类项目的完整流程进行了讲解。需要注意的几点如下:
(1)在本项目中保存的是推理模型,和checkpoint是不同的,具体的讲解大家可以查看官方API讲解。
(2)数据集中,label的类型需要是int64格式,并且需要扩充一个维度。
(3)关于模型的详细训练过程讲解以及高层API的详细讲解,大家可以参考Paddle2.0应用案例–迁移学习。
我目前在上海,感兴趣的领域包括模型压缩、小目标检测、嵌入式,欢迎交流关注。来AI Studio互粉吧等你哦