在飞桨平台做图像分类
前言
计划是在寒假时用在飞桨平台上做动物,水果的分类。
制作数据集
代码在文章最后
下载数据集
飞桨有内置数据集和自定义数据集,这里主要是写如何制作自定义数据集。我这里用到的数据集就是第十六届智能车视觉AI组组委会提供的数据集:这里放上百度网盘链接:
动物水果数据集l
提取码:lasl
只需要下载动物水果即可。
飞桨数据集
飞桨有 map-style 的 paddle.io.Dataset 基类 和 iterable-style 的 paddle.io.IterableDataset 基类 ,来完成数据集定义。此外,针对一些特殊的场景,飞桨框架也提供了 paddle.io.TensorDataset 基类,可以直接处理 Tensor 数据为 dataset,一键完成数据集的定义。这里用的是基于paddle.io.Dataset的,也是官方更为推荐使用的API.使用 paddle.io.Dataset,最后会返回一个 map-style 的 Dataset 类。可以用于后续的数据增强、数据加载等。
使用 paddle.io.Dataset 只需要按格式完成以下四步即可。
步骤一:继承paddle.io.IterableDataset类
步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集
步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
步骤四:实现__len__方法,返回数据集总数目
在下面将会逐步实现这些步骤
制作飞桨数据集
- 继承paddle.io.IterableDataset类
import os
import random
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
import paddle
class myreader(paddle.io.Dataset):
if __name__ == '__main__':
pass
- 实现构造函数,定义数据读取方式,划分训练和测试数据集
将数据集按照数字索引的方式命名,要处理的文件路径是这样的:
0~9是分别是5个动物和5个水果大类,里面分别有各类png图片100张左右。
用os.path.join()方法来拼接路径,遍历得到每一张图片的路径。
然后用os.path.splitext()来判段文件是否是.png后缀的,这个方法会将文件名和文件后缀分开,os.path.splitext(文件路径)[-1]所读取到的就是后缀。
然后用cv.imread来读取图片,输入参数有两个,一个是路径,一个是读取的色彩选择,可以选择bgr彩图还是灰度图,默认bgr彩图,注意这个顺序是bgr,而不是常见的rgb,如果读取完后直接用plt来显示的话,图像的色彩就会出错。
所以我们用cv.resize()来对图像的大小以及色彩进行修改,cv.resize(img, (64, 64))[…, (2, 1, 0)],这是指将图像放缩为64×64大小的rgb图片。(这里修改图像大小的步骤不能省去,否则数组形状不一,后面会报错或警告)
我们需要将整组图片分为训练集以及测试集,这两个集合不能有重叠部分。这里用train_ratio作为参数来指定训练集的占比,然后用train_ratio*10与图片索引相比来决定是训练集还是测试集,这样的话对于相同的一组图片以及相同的train_ratio来说其训练集和测试集完全没有重叠
具体代码如下:
"""
file_path:大文件夹路径
train_ratio:训练集的占比 0~1
index_num:指大文件夹下每个小分类文件的总数
mode: 训练集还是测试集
"""
def __init__(self,file_path,train_ratio,index_num,mode):
super(myreader, self).__init__()
# self.all_data=[]
# self.all_lable=[]
self.mode = mode
self.train_data = []
self.train_lable = []
self.test_data = []
self.test_lable = []
self.file_path = file_path
self.train_ratio = train_ratio
dataindex = 0
for i in range(index_num):
file_path = os.path.join(self.file_path,'%d' % i)
for j in os.listdir(file_path):
dataindex = dataindex % 10
if(os.path.splitext(j)[-1] == '.png'):
img = cv.imread(os.path.join(file_path, j))
img = cv.resize(img, (64, 64))[..., (2, 1, 0)]
if mode == 'train':
if dataindex < train_ratio*10:
self.train_data.append(img/255)
self.train_lable.append(i)
else:
if dataindex >= train_ratio*10:
self.test_data.append(img)
self.test_lable.append(i)
dataindex += 1
- 实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据
def __getitem__(self,index):
if self.mode == 'train':
npData = np.asarray(self.train_data,dtype='float32')[index]
npLable = np.asarray(self.train_lable,dtype='int64')[index]
return npData,npLable
else:
npData = np.asarray(self.test_data,dtype='float32')[index]
npLable = np.asarray(self.test_lable,dtype='int64')[index]
return npData, npLable
- 实现__len__方法,返回数据集总数目
注意len方法所对应的值要和getitem的值相等,就是说如果要用getitem取训练集的话,相对的len方法也要返回训练集的数目。
def __len__(self):
if self.mode == 'train':
return len(self.train_data)
else:
return len(self.test_data)
数据集的加载
当我们定义了数据集后,就需要加载数据集。我们可以通过 paddle.io.DataLoader 完成数据的加载。
train_dataset = myreader(r'picture',0.7,2,'train')
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
完整代码
import os
import numpy as np
import cv2 as cv
# import matplotlib.pyplot as plt
import paddle
class myreader(paddle.io.Dataset):
"""
继承paddle.io.Dataset类
"""
"""
file_path:大文件夹路径
train_ratio:训练集的占比 0~1
index_num:指大文件夹下每个小分类文件的总数
mode: 训练集还是测试集
"""
def __init__(self,file_path,train_ratio,index_num,mode):
super(myreader, self).__init__()
# self.all_data=[]
# self.all_lable=[]
self.mode = mode
self.train_data = []
self.train_lable = []
self.test_data = []
self.test_lable = []
self.file_path = file_path
self.train_ratio = train_ratio
dataindex = 0
for i in range(index_num):
file_path = os.path.join(self.file_path,'%d' % i)
for j in os.listdir(file_path):
dataindex = dataindex % 10
if(os.path.splitext(j)[-1] == '.png'):
img = cv.imread(os.path.join(file_path, j))
img = cv.resize(img, (64, 64))[..., (2, 1, 0)]
if mode == 'train':
if dataindex < train_ratio*10:
self.train_data.append(img/255)
self.train_lable.append(i)
else:
if dataindex >= train_ratio*10:
self.test_data.append(img)
self.test_lable.append(i)
dataindex += 1
def __getitem__(self,index):
if self.mode == 'train':
npData = np.asarray(self.train_data,dtype='float32')[index]
npLable = np.asarray(self.train_lable,dtype='int64')[index]
return npData,npLable
else:
npData = np.asarray(self.test_data,dtype='float32')[index]
npLable = np.asarray(self.test_lable,dtype='int64')[index]
return npData, npLable
def __len__(self):
if self.mode == 'train':
return len(self.train_data)
else:
return len(self.test_data)
if __name__ == '__main__':
import matplotlib.pyplot as plt
train_dataset = myreader(r'animal_fruit',0.7,1,'train')
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = myreader(r'animal_fruit',0.7,1,'test')
test_loader = paddle.io.DataLoader(test_dataset, batch_size=64, shuffle=True)
for batch_id, data in enumerate(train_loader()):
x_data = data[0]
y_data = data[1]
print(x_data.numpy().dtype)
print(y_data.numpy().shape)
# for batch_id, data in enumerate(test_loader()):
# x_data = data[0]
# y_data = data[1]
# print(x_data.numpy().shape)
# print(y_data.numpy().shape)
print(train_dataset[1][0])
l = np.array(train_dataset[0][0])
plt.figure(figsize=(2,2))
plt.imshow(l, cmap=plt.cm.binary)
测试:
from work import myImageReader
import paddle
import matplotlib.pyplot as plt
import numpy as np
train_dataset = myImageReader.myreader(r'animal',0.7,1,'train')
# print(train_dataset[1][0])
l = np.array(train_dataset[0][0])
plt.figure(figsize=(2,2))
plt.imshow(l, cmap=plt.cm.binary)